3
* Copyright (C) 1999, 2000 Red Hat Inc.
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Library General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Library General Public License for more details.
15
* You should have received a copy of the GNU Library General Public
16
* License along with this library; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
22
#include <gconf/gconf-backend.h>
23
#include <gconf/gconf-internals.h>
24
#include <gconf/gconf.h>
26
#include "xml-cache.h"
29
#include <libxml/tree.h>
30
#include <libxml/parser.h>
37
#include <sys/types.h>
47
* Basically we have a directory tree underneath an arbitrary root
48
* directory. The directory tree reflects the configuration
49
* namespace. Each directory contains an XML file which contains
50
* metadata for the directory and the key-value pairs in that
51
* directory. The magic file in each directory is called %gconf.xml,
52
* and can't clash with the database namespace because names containing
53
* % aren't allowed. So:
65
* Locking doesn't _really_ matter because there's only one instance
66
* of the daemon at a time. However, eventually we want a non-daemon
67
* command line tool and library, e.g. for the debconf stuff,
68
* so we will eventually have locking. I'll figure out then how
73
* I haven't decided the best way to do caching yet. As a first cut;
74
* we'll cache the parse tree for any files we've looked at. The cache
75
* will contain time stamps; we'll nuke cache entries that haven't been
76
* used in a while, either in a main loop timeout or by checking whenever
77
* we add a new cache entry. Parse trees correspond to "directories" in the
78
* configuration namespace.
80
* A more precise cache will store specific key-value pairs; this cache
81
* will probably contain a pointer to the parse tree node the key-value
84
* We'll of course need a "dirty" list of stuff not yet written to disk.
86
* We'll save the mod time of parse trees when we load them, so we can
87
* paranoia check that no one has change the file before we save.
89
* Ideally we could monitor our own process size and also free up
90
* cache whenever we started to use massive RAM. However, not sure
91
* this can be done at all portably. Could possibly have some measure
94
* The libxml parse trees are pretty huge, so in theory we could
95
* "compress" them by extracting all the information we want into a
96
* specialized data structure, then nuking the parse tree. However,
97
* that would add more CPU overhead at load and save time. Anyway, as
98
* a first cut I'm not going to do this, we might do it later.
102
* We'll want to save atomically by creating a temporary file for the
103
* new file version, renaming the original file, moving the temporary
104
* file into place, then deleting the original file, checking for
105
* errors and mod times along the way.
107
* Failed lookup caching
109
* If a key/directory doesn't exist, we create a cache entry anyway
110
* so we can rapidly re-determine that it doesn't exist.
111
* We also need to save "dirty" nonexistent entries, so we can delete
112
* the stuff off disk.
116
typedef struct _XMLSource XMLSource;
121
GConfSource source; /* inherit from GConfSource */
130
static XMLSource* xs_new (const gchar* root_dir,
134
static void xs_destroy (XMLSource* source);
140
/* shutdown() is a BSD libc function */
141
static void x_shutdown (GError** err);
143
static GConfSource* resolve_address (const gchar* address,
146
static void lock (GConfSource* source,
149
static void unlock (GConfSource* source,
152
static gboolean readable (GConfSource* source,
156
static gboolean writable (GConfSource* source,
160
static GConfValue* query_value (GConfSource* source,
162
const gchar** locales,
166
static GConfMetaInfo*query_metainfo (GConfSource* source,
170
static void set_value (GConfSource* source,
175
static GSList* all_entries (GConfSource* source,
177
const gchar** locales,
180
static GSList* all_subdirs (GConfSource* source,
184
static void unset_value (GConfSource* source,
189
static gboolean dir_exists (GConfSource *source,
193
static void remove_dir (GConfSource* source,
197
static void set_schema (GConfSource* source,
199
const gchar* schema_key,
202
static gboolean sync_all (GConfSource* source,
205
static void destroy_source (GConfSource* source);
207
static void clear_cache (GConfSource* source);
209
static GConfBackendVTable xml_vtable = {
231
x_shutdown (GError** err)
233
gconf_log(GCL_DEBUG, _("Unloading XML backend module."));
237
lock (GConfSource* source,
245
unlock (GConfSource* source,
253
readable (GConfSource* source,
262
writable (GConfSource* source,
271
resolve_address (const gchar* address, GError** err)
278
GConfLock* lock = NULL;
279
guint dir_mode = 0700;
280
guint file_mode = 0600;
281
gchar** address_flags;
283
gboolean force_readonly;
285
root_dir = gconf_address_resource(address);
287
if (root_dir == NULL)
289
gconf_set_error(err, GCONF_ERROR_BAD_ADDRESS, _("Couldn't find the XML root directory in the address `%s'"), address);
293
/* Chop trailing '/' to canonicalize */
294
len = strlen(root_dir);
296
if (root_dir[len-1] == '/')
297
root_dir[len-1] = '\0';
299
if (mkdir(root_dir, dir_mode) < 0)
303
gconf_set_error(err, GCONF_ERROR_FAILED,
304
_("Could not make directory `%s': %s"),
305
(gchar*)root_dir, strerror(errno));
311
/* Already exists, base our dir_mode on it */
313
if (stat(root_dir, &statbuf) == 0)
315
dir_mode = mode_t_to_mode(statbuf.st_mode);
316
/* dir_mode without search bits */
317
file_mode = dir_mode & (~0111);
322
force_readonly = FALSE;
324
address_flags = gconf_address_flags (address);
327
iter = address_flags;
330
if (strcmp (*iter, "readonly") == 0)
332
force_readonly = TRUE;
340
g_strfreev (address_flags);
343
/* See if we're writable */
352
testfile = g_strconcat(root_dir, "/.testing.writeability", NULL);
354
fd = open(testfile, O_CREAT|O_WRONLY, S_IRWXU);
368
flags |= GCONF_SOURCE_ALL_WRITEABLE;
370
/* We only do locking if it's writable,
371
which is sort of broken but close enough
377
lockdir = gconf_concat_dir_and_key(root_dir, "%gconf-xml-backend.lock");
379
lock = gconf_get_lock(lockdir, err);
382
gconf_log(GCL_DEBUG, "Acquired lock directory `%s'", lockdir);
395
/* see if we're readable */
396
gboolean readable = FALSE;
399
d = opendir(root_dir);
408
flags |= GCONF_SOURCE_ALL_READABLE;
411
if (!(flags & GCONF_SOURCE_ALL_READABLE) &&
412
!(flags & GCONF_SOURCE_ALL_WRITEABLE))
414
gconf_set_error(err, GCONF_ERROR_BAD_ADDRESS, _("Can't read from or write to the XML root directory in the address `%s'"), address);
419
/* Create the new source */
421
xsource = xs_new(root_dir, dir_mode, file_mode, lock);
424
_("Directory/file permissions for XML source at root %s are: %o/%o"),
425
root_dir, dir_mode, file_mode);
427
source = (GConfSource*)xsource;
429
source->flags = flags;
437
query_value (GConfSource* source,
439
const gchar** locales,
443
XMLSource* xs = (XMLSource*)source;
446
GError* error = NULL;
448
parent = gconf_key_directory(key);
450
g_assert(parent != NULL);
452
dir = cache_lookup(xs->cache, parent, FALSE, &error);
454
/* We DO NOT want to return an error unless it represents a general
455
problem with the backend; since we don't want to report stuff
456
like "this key doesn't exist yet" - however this is a maintenance
457
problem, since some errors may be added that need reporting. */
460
gconf_log(GCL_WARNING, "%s", error->message);
470
const gchar* relative_key;
473
relative_key = gconf_key_key(key);
475
retval = dir_get_value(dir, relative_key, locales, schema_name, &error);
477
/* perhaps we should be reporting this error... */
480
gconf_log(GCL_WARNING, "%s", error->message);
491
static GConfMetaInfo*
492
query_metainfo (GConfSource* source, const gchar* key,
495
XMLSource* xs = (XMLSource*)source;
499
parent = gconf_key_directory(key);
503
dir = cache_lookup(xs->cache, parent, FALSE, err);
509
const gchar* relative_key;
511
relative_key = gconf_key_key (key);
513
return dir_get_metainfo (dir, relative_key, err);
517
/* No metainfo found */
522
set_value (GConfSource* source, const gchar* key, GConfValue* value,
525
XMLSource* xs = (XMLSource*)source;
529
g_return_if_fail(value != NULL);
530
g_return_if_fail(source != NULL);
532
parent = gconf_key_directory(key);
534
g_assert(parent != NULL);
536
dir = cache_lookup(xs->cache, parent, TRUE, err);
543
g_return_if_fail((err == NULL || *err != NULL));
548
const gchar* relative_key;
550
relative_key = gconf_key_key(key);
552
dir_set_value(dir, relative_key, value, err);
558
all_entries (GConfSource* source,
560
const gchar** locales,
563
XMLSource* xs = (XMLSource*)source;
566
dir = cache_lookup(xs->cache, key, FALSE, err);
571
return dir_all_entries(dir, locales, err);
575
all_subdirs (GConfSource* source,
580
XMLSource* xs = (XMLSource*)source;
582
dir = cache_lookup (xs->cache, key, FALSE, err);
587
return dir_all_subdirs (dir, err);
591
unset_value (GConfSource* source,
596
XMLSource* xs = (XMLSource*)source;
600
gconf_log(GCL_DEBUG, "XML backend: unset value `%s'", key);
602
parent = gconf_key_directory(key);
604
dir = cache_lookup(xs->cache, parent, FALSE, err);
612
const gchar* relative_key;
614
relative_key = gconf_key_key(key);
616
dir_unset_value(dir, relative_key, locale, err);
621
dir_exists (GConfSource*source,
625
XMLSource *xs = (XMLSource*)source;
628
dir = cache_lookup(xs->cache, key, FALSE, err);
630
return (dir != NULL);
634
remove_dir (GConfSource* source,
638
XMLSource* xs = (XMLSource*)source;
641
dir = cache_lookup(xs->cache, key, FALSE, err);
647
dir_mark_deleted(dir);
652
set_schema (GConfSource* source,
654
const gchar* schema_key,
657
XMLSource* xs = (XMLSource*)source;
662
g_return_if_fail(schema_key != NULL);
664
parent = gconf_key_directory(key);
666
g_assert(parent != NULL);
668
dir = cache_lookup(xs->cache, parent, TRUE, err);
674
return; /* error should be set */
677
const gchar* relative_key;
679
relative_key = gconf_key_key(key);
681
dir_set_schema(dir, relative_key, schema_key, err);
686
sync_all (GConfSource* source,
689
XMLSource* xs = (XMLSource*)source;
691
return cache_sync(xs->cache, err);
695
destroy_source (GConfSource* source)
697
xs_destroy((XMLSource*)source);
701
clear_cache (GConfSource* source)
703
XMLSource* xs = (XMLSource*)source;
705
/* clean all entries older than 0 seconds */
706
cache_clean(xs->cache, 0);
711
G_MODULE_EXPORT const gchar*
712
g_module_check_init (GModule *module)
714
gconf_log(GCL_DEBUG, _("Initializing XML backend module"));
719
G_MODULE_EXPORT GConfBackendVTable*
720
gconf_backend_get_vtable(void)
725
/* ****************************************************/
731
/* This timeout periodically cleans up
732
the old cruft in the cache */
734
cleanup_timeout(gpointer data)
736
XMLSource* xs = (XMLSource*)data;
738
cache_clean(xs->cache, 60*5 /* 5 minutes */);
744
xs_new (const gchar* root_dir, guint dir_mode, guint file_mode, GConfLock* lock)
748
g_return_val_if_fail(root_dir != NULL, NULL);
750
xs = g_new0(XMLSource, 1);
752
xs->root_dir = g_strdup(root_dir);
754
xs->cache = cache_new(xs->root_dir, dir_mode, file_mode);
756
xs->timeout_id = g_timeout_add(1000*60*5, /* 1 sec * 60 s/min * 5 min */
762
xs->dir_mode = dir_mode;
763
xs->file_mode = file_mode;
769
xs_destroy (XMLSource* xs)
771
GError* error = NULL;
773
g_return_if_fail(xs != NULL);
775
/* do this first in case we're in a "fast cleanup just before exit"
777
if (xs->lock != NULL && !gconf_release_lock(xs->lock, &error))
779
gconf_log(GCL_ERR, _("Failed to give up lock on XML dir `%s': %s"),
780
xs->root_dir, error->message);
785
if (!g_source_remove(xs->timeout_id))
787
/* should not happen, don't translate */
788
gconf_log(GCL_ERR, "timeout not found to remove?");
791
cache_destroy(xs->cache);
792
g_free(xs->root_dir);