1 
2 /* GConf
3  * Copyright (C) 1999, 2000 Red Hat Inc.
4  *
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.
9  *
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.
14  *
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., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include <config.h>
22 #include "gconf/gconf-backend.h"
23 #include "gconf/gconf-internals.h"
24 #include "gconf/gconf.h"
25 
26 #include "xml-cache.h"
27 
28 
29 #include <libxml/tree.h>
30 #include <libxml/parser.h>
31 
32 #include <stdio.h>
33 #include <time.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <limits.h>
42 
43 /*
44  * Overview
45  *
46  * Basically we have a directory tree underneath an arbitrary root
47  * directory.  The directory tree reflects the configuration
48  * namespace. Each directory contains an XML file which contains
49  * metadata for the directory and the key-value pairs in that
50  * directory.  The magic file in each directory is called %gconf.xml,
51  * and can't clash with the database namespace because names containing
52  * % aren't allowed.  So:
53  *
54  * /
55  *  %gconf.xml
56  *   guppi/
57  *     %gconf.xml
58  *   gnumeric/
59  *     %gconf.xml
60  *
61  *
62  * Locking
63  *
64  * Locking doesn't _really_ matter because there's only one instance
65  * of the daemon at a time. However, eventually we want a non-daemon
66  * command line tool and library, e.g. for the debconf stuff,
67  * so we will eventually have locking. I'll figure out then how
68  * it will work.
69  *
70  * Caching
71  *
72  * I haven't decided the best way to do caching yet. As a first cut;
73  * we'll cache the parse tree for any files we've looked at. The cache
74  * will contain time stamps; we'll nuke cache entries that haven't been
75  * used in a while, either in a main loop timeout or by checking whenever
76  * we add a new cache entry. Parse trees correspond to "directories" in the
77  * configuration namespace.
78  *
79  * A more precise cache will store specific key-value pairs; this cache
80  * will probably contain a pointer to the parse tree node the key-value
81  * pair is inside.
82  *
83  * We'll of course need a "dirty" list of stuff not yet written to disk.
84  *
85  * We'll save the mod time of parse trees when we load them, so we can
86  * paranoia check that no one has change the file before we save.
87  *
88  * Ideally we could monitor our own process size and also free up
89  * cache whenever we started to use massive RAM. However, not sure
90  * this can be done at all portably. Could possibly have some measure
91  * of parse tree size.
92  *
93  * The libxml parse trees are pretty huge, so in theory we could
94  * "compress" them by extracting all the information we want into a
95  * specialized data structure, then nuking the parse tree. However,
96  * that would add more CPU overhead at load and save time. Anyway, as
97  * a first cut I'm not going to do this, we might do it later.
98  *
99  * Atomic Saving
100  *
101  * We'll want to save atomically by creating a temporary file for the
102  * new file version, renaming the original file, moving the temporary
103  * file into place, then deleting the original file, checking for
104  * errors and mod times along the way.
105  *
106  * Failed lookup caching
107  *
108  * If a key/directory doesn't exist, we create a cache entry anyway
109  * so we can rapidly re-determine that it doesn't exist.
110  * We also need to save "dirty" nonexistent entries, so we can delete
111  * the stuff off disk.
112  *
113  */
114 
115 typedef struct _XMLSource XMLSource;
116 
117 /* XMLSource **/
118 
119 struct _XMLSource {
120   GConfSource source; /* inherit from GConfSource */
121   Cache* cache;
122   gchar* root_dir;
123   guint timeout_id;
124   GConfLock* lock;
125   guint dir_mode;
126   guint file_mode;
127 };
128 
129 static XMLSource* xs_new       (const gchar* root_dir,
130                                 guint dir_mode,
131                                 guint file_mode,
132                                 GConfLock* lock);
133 static void       xs_destroy   (XMLSource* source);
134 
135 /*
136  * VTable functions
137  */
138 
139  /* shutdown() is a BSD libc function */
140 static void          x_shutdown        (GError** err);
141 
142 static GConfSource*  resolve_address (const gchar* address,
143                                       GError** err);
144 
145 static void          lock            (GConfSource* source,
146                                       GError** err);
147 
148 static void          unlock          (GConfSource* source,
149                                       GError** err);
150 
151 static gboolean     readable         (GConfSource* source,
152                                       const gchar* key,
153                                       GError** err);
154 
155 static gboolean     writable        (GConfSource* source,
156                                       const gchar* key,
157                                       GError** err);
158 
159 static GConfValue*   query_value     (GConfSource* source,
160                                       const gchar* key,
161                                       const gchar** locales,
162                                       gchar** schema_name,
163                                       GError** err);
164 
165 static GConfMetaInfo*query_metainfo  (GConfSource* source,
166                                       const gchar* key,
167                                       GError** err);
168 
169 static void          set_value       (GConfSource* source,
170                                       const gchar* key,
171                                       const GConfValue* value,
172                                       GError** err);
173 
174 static GSList*       all_entries    (GConfSource* source,
175                                      const gchar* dir,
176                                      const gchar** locales,
177                                      GError** err);
178 
179 static GSList*       all_subdirs     (GConfSource* source,
180                                       const gchar* dir,
181                                       GError** err);
182 
183 static void          unset_value     (GConfSource* source,
184                                       const gchar* key,
185                                       const gchar* locale,
186                                       GError** err);
187 
188 static gboolean      dir_exists      (GConfSource *source,
189                                       const gchar *dir,
190                                       GError** err);
191 
192 static void          remove_dir      (GConfSource* source,
193                                       const gchar* dir,
194                                       GError** err);
195 
196 static void          set_schema      (GConfSource* source,
197                                       const gchar* key,
198                                       const gchar* schema_key,
199                                       GError** err);
200 
201 static gboolean      sync_all        (GConfSource* source,
202                                       GError** err);
203 
204 static void          destroy_source  (GConfSource* source);
205 
206 static void          clear_cache     (GConfSource* source);
207 
208 static void          blow_away_locks (const char *address);
209 
210 static GConfBackendVTable xml_vtable = {
211   sizeof (GConfBackendVTable),
212   x_shutdown,
213   resolve_address,
214   lock,
215   unlock,
216   readable,
217   writable,
218   query_value,
219   query_metainfo,
220   set_value,
221   all_entries,
222   all_subdirs,
223   unset_value,
224   dir_exists,
225   remove_dir,
226   set_schema,
227   sync_all,
228   destroy_source,
229   clear_cache,
230   blow_away_locks,
231   NULL, /* set_notify_func */
232   NULL, /* add_listener    */
233   NULL  /* remove_listener */
234 };
235 
236 static void
x_shutdown(GError ** err)237 x_shutdown (GError** err)
238 {
239   gconf_log(GCL_DEBUG, _("Unloading XML backend module."));
240 }
241 
242 static void
lock(GConfSource * source,GError ** err)243 lock (GConfSource* source,
244       GError** err)
245 {
246 
247 
248 }
249 
250 static void
unlock(GConfSource * source,GError ** err)251 unlock (GConfSource* source,
252         GError** err)
253 {
254 
255 
256 }
257 
258 static gboolean
readable(GConfSource * source,const gchar * key,GError ** err)259 readable (GConfSource* source,
260           const gchar* key,
261           GError** err)
262 {
263 
264   return TRUE;
265 }
266 
267 static gboolean
writable(GConfSource * source,const gchar * key,GError ** err)268 writable (GConfSource* source,
269            const gchar* key,
270            GError** err)
271 {
272 
273   return TRUE;
274 }
275 
276 static char*
get_dir_from_address(const char * address,GError ** err)277 get_dir_from_address (const char *address,
278                       GError    **err)
279 {
280   char *root_dir;
281   int len;
282 
283   root_dir = gconf_address_resource (address);
284 
285   if (root_dir == NULL)
286     {
287       gconf_set_error (err, GCONF_ERROR_BAD_ADDRESS,
288                        _("Couldn't find the XML root directory in the address `%s'"),
289                        address);
290       return NULL;
291     }
292 
293   /* Chop trailing '/' to canonicalize */
294   len = strlen (root_dir);
295 
296   if (root_dir[len-1] == '/')
297     root_dir[len-1] = '\0';
298 
299   return root_dir;
300 }
301 
302 static char*
get_lock_dir_from_root_dir(const char * root_dir)303 get_lock_dir_from_root_dir (const char *root_dir)
304 {
305   gchar* lockdir;
306 
307   lockdir = gconf_concat_dir_and_key (root_dir, "%gconf-xml-backend.lock");
308 
309   return lockdir;
310 }
311 
312 static GConfSource*
resolve_address(const gchar * address,GError ** err)313 resolve_address (const gchar* address, GError** err)
314 {
315   struct stat statbuf;
316   gchar* root_dir;
317   XMLSource* xsource;
318   GConfSource* source;
319   gint flags = 0;
320   GConfLock* lock = NULL;
321   guint dir_mode = 0700;
322   guint file_mode = 0600;
323   gchar** address_flags;
324   gchar** iter;
325   gboolean force_readonly;
326 
327   root_dir = get_dir_from_address (address, err);
328   if (root_dir == NULL)
329     return NULL;
330 
331   if (g_stat (root_dir, &statbuf) == 0)
332     {
333       /* Already exists, base our dir_mode on it */
334       dir_mode = _gconf_mode_t_to_mode (statbuf.st_mode);
335 
336       /* dir_mode without search bits */
337       file_mode = dir_mode & (~0111);
338     }
339   else if (g_mkdir (root_dir, dir_mode) < 0)
340     {
341       /* Error out even on EEXIST - shouldn't happen anyway */
342       gconf_set_error (err, GCONF_ERROR_FAILED,
343 		       _("Could not make directory `%s': %s"),
344 		      (gchar *)root_dir, g_strerror (errno));
345       g_free (root_dir);
346       return NULL;
347     }
348 
349   force_readonly = FALSE;
350 
351   address_flags = gconf_address_flags (address);
352   if (address_flags)
353     {
354       iter = address_flags;
355       while (*iter)
356         {
357           if (strcmp (*iter, "readonly") == 0)
358             {
359               force_readonly = TRUE;
360               break;
361             }
362 
363           ++iter;
364         }
365     }
366 
367   g_strfreev (address_flags);
368 
369   {
370     /* See if we're writable */
371     gboolean writable;
372     int fd;
373     gchar* testfile;
374 
375     writable = FALSE;
376 
377     if (!force_readonly)
378       {
379         testfile = g_strconcat(root_dir, "/.testing.writeability", NULL);
380 
381         fd = g_open(testfile, O_CREAT|O_WRONLY, S_IRWXU);
382 
383         if (fd >= 0)
384           {
385             writable = TRUE;
386             close(fd);
387           }
388 
389         g_unlink(testfile);
390 
391         g_free(testfile);
392       }
393 
394     if (writable)
395       flags |= GCONF_SOURCE_ALL_WRITEABLE;
396 
397 #ifdef HAVE_CORBA
398     /* We only do locking if it's writable,
399      * and if not using local locks,
400      * which is sort of broken but close enough
401      */
402     if (writable && !gconf_use_local_locks ())
403       {
404         gchar* lockdir;
405 
406         lockdir = get_lock_dir_from_root_dir (root_dir);
407 
408         lock = gconf_get_lock(lockdir, err);
409 
410         if (lock != NULL)
411           gconf_log(GCL_DEBUG, "Acquired lock directory `%s'", lockdir);
412 
413         g_free(lockdir);
414 
415         if (lock == NULL)
416           {
417             g_free(root_dir);
418             return NULL;
419           }
420       }
421 #endif
422   }
423 
424   {
425     /* see if we're readable */
426     gboolean readable = FALSE;
427     GDir* d;
428 
429     d = g_dir_open(root_dir, 0, NULL);
430 
431     if (d != NULL)
432       {
433         readable = TRUE;
434         g_dir_close(d);
435       }
436 
437     if (readable)
438       flags |= GCONF_SOURCE_ALL_READABLE;
439   }
440 
441   if (!(flags & GCONF_SOURCE_ALL_READABLE) &&
442       !(flags & GCONF_SOURCE_ALL_WRITEABLE))
443     {
444       gconf_set_error(err, GCONF_ERROR_BAD_ADDRESS, _("Can't read from or write to the XML root directory in the address \"%s\""), address);
445       g_free(root_dir);
446       return NULL;
447     }
448 
449   /* Create the new source */
450 
451   xsource = xs_new(root_dir, dir_mode, file_mode, lock);
452 
453   gconf_log(GCL_DEBUG,
454             _("Directory/file permissions for XML source at root %s are: %o/%o"),
455             root_dir, dir_mode, file_mode);
456 
457   source = (GConfSource*)xsource;
458 
459   source->flags = flags;
460 
461   g_free(root_dir);
462 
463   return source;
464 }
465 
466 static GConfValue*
query_value(GConfSource * source,const gchar * key,const gchar ** locales,gchar ** schema_name,GError ** err)467 query_value (GConfSource* source,
468              const gchar* key,
469              const gchar** locales,
470              gchar** schema_name,
471              GError** err)
472 {
473   XMLSource* xs = (XMLSource*)source;
474   gchar* parent;
475   Dir* dir;
476   GError* error = NULL;
477 
478   parent = gconf_key_directory(key);
479 
480   g_assert(parent != NULL);
481 
482   dir = cache_lookup(xs->cache, parent, FALSE, &error);
483 
484   /* We DO NOT want to return an error unless it represents a general
485      problem with the backend; since we don't want to report stuff
486      like "this key doesn't exist yet" - however this is a maintenance
487      problem, since some errors may be added that need reporting. */
488   if (error != NULL)
489     {
490       gconf_log(GCL_WARNING, "%s", error->message);
491       g_error_free(error);
492       error = NULL;
493     }
494 
495   g_free(parent);
496   parent = NULL;
497 
498   if (dir != NULL)
499     {
500       const gchar* relative_key;
501       GConfValue* retval;
502 
503       relative_key = gconf_key_key(key);
504 
505       retval = dir_get_value(dir, relative_key, locales, schema_name, &error);
506 
507       /* perhaps we should be reporting this error... */
508       if (error != NULL)
509         {
510           gconf_log(GCL_WARNING, "%s", error->message);
511           g_error_free(error);
512           error = NULL;
513         }
514 
515       return retval;
516     }
517   else
518     return NULL;
519 }
520 
521 static GConfMetaInfo*
query_metainfo(GConfSource * source,const gchar * key,GError ** err)522 query_metainfo  (GConfSource* source, const gchar* key,
523                  GError** err)
524 {
525   XMLSource* xs = (XMLSource*)source;
526   gchar* parent;
527   Dir* dir;
528 
529   parent = gconf_key_directory(key);
530 
531   if (parent != NULL)
532     {
533       dir = cache_lookup(xs->cache, parent, FALSE, err);
534       g_free(parent);
535       parent = NULL;
536 
537       if (dir != NULL)
538         {
539           const gchar* relative_key;
540 
541           relative_key = gconf_key_key (key);
542 
543           return dir_get_metainfo (dir, relative_key, err);
544         }
545     }
546 
547   /* No metainfo found */
548   return NULL;
549 }
550 
551 static void
set_value(GConfSource * source,const gchar * key,const GConfValue * value,GError ** err)552 set_value (GConfSource* source, const gchar* key, const GConfValue* value,
553            GError** err)
554 {
555   XMLSource* xs = (XMLSource*)source;
556   Dir* dir;
557   gchar* parent;
558 
559   g_return_if_fail(value != NULL);
560   g_return_if_fail(source != NULL);
561 
562   parent = gconf_key_directory(key);
563 
564   g_assert(parent != NULL);
565 
566   dir = cache_lookup(xs->cache, parent, TRUE, err);
567 
568   g_free(parent);
569   parent = NULL;
570 
571   if (dir == NULL)
572     {
573       g_return_if_fail((err == NULL || *err != NULL));
574       return;
575     }
576   else
577     {
578       const gchar* relative_key;
579 
580       relative_key = gconf_key_key(key);
581 
582       dir_set_value(dir, relative_key, value, err);
583     }
584 }
585 
586 
587 static GSList*
all_entries(GConfSource * source,const gchar * key,const gchar ** locales,GError ** err)588 all_entries    (GConfSource* source,
589                 const gchar* key,
590                 const gchar** locales,
591                 GError** err)
592 {
593   XMLSource* xs = (XMLSource*)source;
594   Dir* dir;
595 
596   dir = cache_lookup(xs->cache, key, FALSE, err);
597 
598   if (dir == NULL)
599     return NULL;
600   else
601     return dir_all_entries(dir, locales, err);
602 }
603 
604 static GSList*
all_subdirs(GConfSource * source,const gchar * key,GError ** err)605 all_subdirs     (GConfSource* source,
606                  const gchar* key,
607                  GError** err)
608 {
609   Dir* dir;
610   XMLSource* xs = (XMLSource*)source;
611   GError *sync_err;
612 
613   /* We have to sync before we can do this, to see which
614    * subdirs have gone away.
615    */
616   sync_err = NULL;
617   cache_sync (xs->cache, &sync_err);
618   if (sync_err)
619     {
620       gconf_log (GCL_WARNING, _("Error syncing the XML backend directory cache: %s"),
621                  sync_err->message);
622       g_error_free (sync_err);
623       sync_err = NULL;
624       /* continue, may as well try our best. */
625     }
626 
627   dir = cache_lookup (xs->cache, key, FALSE, err);
628 
629   if (dir == NULL)
630     return NULL;
631   else
632     return dir_all_subdirs (dir, err);
633 }
634 
635 static void
unset_value(GConfSource * source,const gchar * key,const gchar * locale,GError ** err)636 unset_value     (GConfSource* source,
637                  const gchar* key,
638                  const gchar* locale,
639                  GError** err)
640 {
641   XMLSource* xs = (XMLSource*)source;
642   Dir* dir;
643   gchar* parent;
644 
645   gconf_log(GCL_DEBUG, "XML backend: unset value `%s'", key);
646 
647   parent = gconf_key_directory(key);
648 
649   dir = cache_lookup(xs->cache, parent, FALSE, err);
650 
651   g_free(parent);
652 
653   if (dir == NULL)
654     return;
655   else
656     {
657       const gchar* relative_key;
658 
659       relative_key = gconf_key_key(key);
660 
661       dir_unset_value(dir, relative_key, locale, err);
662     }
663 }
664 
665 static gboolean
dir_exists(GConfSource * source,const gchar * key,GError ** err)666 dir_exists      (GConfSource*source,
667                  const gchar* key,
668                  GError** err)
669 {
670   XMLSource *xs = (XMLSource*)source;
671   Dir* dir;
672 
673   dir = cache_lookup(xs->cache, key, FALSE, err);
674 
675   return (dir != NULL);
676 }
677 
678 static void
remove_dir(GConfSource * source,const gchar * key,GError ** err)679 remove_dir      (GConfSource* source,
680                  const gchar* key,
681                  GError** err)
682 {
683   g_set_error (err, GCONF_ERROR,
684                GCONF_ERROR_FAILED,
685                _("Remove directory operation is no longer supported, just remove all the values in the directory"));
686 }
687 
688 static void
set_schema(GConfSource * source,const gchar * key,const gchar * schema_key,GError ** err)689 set_schema (GConfSource *source,
690             const gchar *key,
691             const gchar *schema_key,
692             GError     **err)
693 {
694   XMLSource* xs = (XMLSource*)source;
695 
696   Dir* dir;
697   gchar* parent;
698 
699   g_return_if_fail (source != NULL);
700   g_return_if_fail (key != NULL);
701 
702   parent = gconf_key_directory (key);
703 
704   g_assert (parent != NULL);
705 
706   dir = cache_lookup (xs->cache, parent, TRUE, err);
707 
708   g_free (parent);
709   parent = NULL;
710 
711   if (dir == NULL)
712     return; /* error should be set */
713   else
714     {
715       const gchar* relative_key;
716 
717       relative_key = gconf_key_key (key);
718 
719       dir_set_schema (dir, relative_key, schema_key, err);
720     }
721 }
722 
723 static gboolean
sync_all(GConfSource * source,GError ** err)724 sync_all        (GConfSource* source,
725                  GError** err)
726 {
727   XMLSource* xs = (XMLSource*)source;
728 
729   return cache_sync (xs->cache, err);
730 }
731 
732 static void
destroy_source(GConfSource * source)733 destroy_source  (GConfSource* source)
734 {
735   xs_destroy((XMLSource*)source);
736 }
737 
738 static void
clear_cache(GConfSource * source)739 clear_cache     (GConfSource* source)
740 {
741   XMLSource* xs = (XMLSource*)source;
742 
743   /* clean all entries older than 0 seconds */
744   cache_clean(xs->cache, 0);
745 }
746 
747 static void
blow_away_locks(const char * address)748 blow_away_locks (const char *address)
749 {
750   char *root_dir;
751   char *lock_dir;
752   GDir *dp;
753   const char *dent;
754 
755   /* /tmp locks should never be stuck, and possible security issue to
756    * blow them away
757    */
758   if (gconf_use_local_locks ())
759     return;
760 
761   root_dir = get_dir_from_address (address, NULL);
762   if (root_dir == NULL)
763     return;
764 
765   lock_dir = get_lock_dir_from_root_dir (root_dir);
766 
767   dp = g_dir_open (lock_dir, 0, NULL);
768 
769   if (dp == NULL)
770     {
771       g_printerr (_("Could not open lock directory for %s to remove locks: %s\n"),
772                   address, g_strerror (errno));
773       goto out;
774     }
775 
776   while ((dent = g_dir_read_name (dp)) != NULL)
777     {
778       char *path;
779 
780       path = g_build_filename (lock_dir, dent, NULL);
781 
782       if (g_unlink (path) < 0)
783         {
784           g_printerr (_("Could not remove file %s: %s\n"),
785                       path, g_strerror (errno));
786         }
787 
788       g_free (path);
789     }
790 
791  out:
792 
793   if (dp)
794     g_dir_close (dp);
795 
796   g_free (root_dir);
797   g_free (lock_dir);
798 }
799 
800 /* Initializer */
801 
802 #ifndef G_PLATFORM_WIN32
803 /* If we use G_MODULE_EXPORT, *only* thusly marked functions will be
804  * exported, and xml-test uses other ones, too.
805  */
806 G_MODULE_EXPORT
807 #endif
808 const gchar*
g_module_check_init(GModule * module)809 g_module_check_init (GModule *module)
810 {
811   gconf_log(GCL_DEBUG, _("Initializing XML backend module"));
812 
813   LIBXML_TEST_VERSION;
814   xmlKeepBlanksDefault(1);
815 
816   return NULL;
817 }
818 
819 #ifndef G_PLATFORM_WIN32
820 G_MODULE_EXPORT
821 #endif
822 GConfBackendVTable*
gconf_backend_get_vtable(void)823 gconf_backend_get_vtable(void)
824 {
825   return &xml_vtable;
826 }
827 
828 /* ****************************************************/
829 
830 /*
831  *  XMLSource
832  */
833 
834 /* This timeout periodically cleans up
835    the old cruft in the cache */
836 static gboolean
cleanup_timeout(gpointer data)837 cleanup_timeout(gpointer data)
838 {
839   XMLSource* xs = (XMLSource*)data;
840 
841   cache_clean(xs->cache, 60*5 /* 5 minutes */);
842 
843   return TRUE;
844 }
845 
846 static XMLSource*
xs_new(const gchar * root_dir,guint dir_mode,guint file_mode,GConfLock * lock)847 xs_new       (const gchar* root_dir, guint dir_mode, guint file_mode, GConfLock* lock)
848 {
849   XMLSource* xs;
850 
851   g_return_val_if_fail(root_dir != NULL, NULL);
852 
853   xs = g_new0(XMLSource, 1);
854 
855   xs->root_dir = g_strdup(root_dir);
856 
857   xs->cache = cache_get(xs->root_dir, dir_mode, file_mode);
858 
859   xs->timeout_id = g_timeout_add_seconds(60*5, /* 1 sec * 60 s/min * 5 min */
860                                  cleanup_timeout,
861                                  xs);
862 
863   xs->lock = lock;
864 
865   xs->dir_mode = dir_mode;
866   xs->file_mode = file_mode;
867 
868   return xs;
869 }
870 
871 static void
xs_destroy(XMLSource * xs)872 xs_destroy   (XMLSource* xs)
873 {
874 #ifdef HAVE_CORBA
875   GError* error = NULL;
876 #endif
877 
878   g_return_if_fail(xs != NULL);
879 
880 #ifdef HAVE_CORBA
881   /* do this first in case we're in a "fast cleanup just before exit"
882      situation */
883   if (xs->lock != NULL && !gconf_release_lock(xs->lock, &error))
884     {
885       gconf_log (GCL_ERR, _("Failed to give up lock on XML directory \"%s\": %s"),
886                  xs->root_dir, error->message);
887       g_error_free(error);
888       error = NULL;
889     }
890 #endif
891 
892   if (!g_source_remove(xs->timeout_id))
893     {
894       /* should not happen, don't translate */
895       gconf_log(GCL_ERR, "timeout not found to remove?");
896     }
897 
898   cache_unref(xs->cache);
899   g_free(xs->root_dir);
900   g_free(xs);
901 }
902 
903