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-internals.h"
23 #include "gconf-backend.h"
24 #include "gconf-schema.h"
25 #include "gconf.h"
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <locale.h>
36 #include <time.h>
37 #include <math.h>
38 
39 #include <gio/gio.h>
40 
41 #ifdef G_OS_WIN32
42 #include <windows.h>
43 #include <share.h>
44 #define pipe(fds) _pipe(fds, 4096, _O_BINARY)
45 #endif
46 
47 gboolean gconf_log_debug_messages = FALSE;
48 
49 static gboolean gconf_daemon_mode = FALSE;
50 static gchar* daemon_ior = NULL;
51 
52 void
gconf_set_daemon_mode(gboolean setting)53 gconf_set_daemon_mode(gboolean setting)
54 {
55   gconf_daemon_mode = setting;
56 }
57 
58 gboolean
gconf_in_daemon_mode(void)59 gconf_in_daemon_mode(void)
60 {
61   return gconf_daemon_mode;
62 }
63 
64 void
gconf_set_daemon_ior(const gchar * ior)65 gconf_set_daemon_ior(const gchar* ior)
66 {
67   if (daemon_ior != NULL)
68     {
69       g_free(daemon_ior);
70       daemon_ior = NULL;
71     }
72 
73   if (ior != NULL)
74     daemon_ior = g_strdup(ior);
75 }
76 
77 const gchar*
gconf_get_daemon_ior(void)78 gconf_get_daemon_ior(void)
79 {
80   return daemon_ior;
81 }
82 
83 gchar*
gconf_key_directory(const gchar * key)84 gconf_key_directory  (const gchar* key)
85 {
86   const gchar* end;
87   gchar* retval;
88   int len;
89 
90   end = strrchr(key, '/');
91 
92   if (end == NULL)
93     {
94       gconf_log(GCL_ERR, _("No '/' in key \"%s\""), key);
95       return NULL;
96     }
97 
98   len = end-key+1;
99 
100   if (len == 1)
101     {
102       /* Root directory */
103       retval = g_strdup("/");
104     }
105   else
106     {
107       retval = g_malloc(len);
108 
109       strncpy(retval, key, len);
110 
111       retval[len-1] = '\0';
112     }
113 
114   return retval;
115 }
116 
117 const gchar*
gconf_key_key(const gchar * key)118 gconf_key_key        (const gchar* key)
119 {
120   const gchar* end;
121 
122   end = strrchr(key, '/');
123 
124   if (end != NULL)
125     ++end;
126 
127   return end;
128 }
129 
130 /*
131  *  Random stuff
132  */
133 
134 #if HAVE_CORBA
135 GConfValue*
gconf_value_from_corba_value(const ConfigValue * value)136 gconf_value_from_corba_value(const ConfigValue* value)
137 {
138   GConfValue* gval;
139   GConfValueType type = GCONF_VALUE_INVALID;
140 
141   switch (value->_d)
142     {
143     case InvalidVal:
144       return NULL;
145     case IntVal:
146       type = GCONF_VALUE_INT;
147       break;
148     case StringVal:
149       type = GCONF_VALUE_STRING;
150       break;
151     case FloatVal:
152       type = GCONF_VALUE_FLOAT;
153       break;
154     case BoolVal:
155       type = GCONF_VALUE_BOOL;
156       break;
157     case SchemaVal:
158       type = GCONF_VALUE_SCHEMA;
159       break;
160     case ListVal:
161       type = GCONF_VALUE_LIST;
162       break;
163     case PairVal:
164       type = GCONF_VALUE_PAIR;
165       break;
166     default:
167       gconf_log(GCL_DEBUG, "Invalid type in %s", G_STRFUNC);
168       return NULL;
169     }
170 
171   g_assert(GCONF_VALUE_TYPE_VALID(type));
172 
173   gval = gconf_value_new(type);
174 
175   switch (gval->type)
176     {
177     case GCONF_VALUE_INT:
178       gconf_value_set_int(gval, value->_u.int_value);
179       break;
180     case GCONF_VALUE_STRING:
181       if (!g_utf8_validate (value->_u.string_value, -1, NULL))
182         {
183           gconf_log (GCL_ERR, _("Invalid UTF-8 in string value in '%s'"),
184                      value->_u.string_value);
185         }
186       else
187         {
188           gconf_value_set_string(gval, value->_u.string_value);
189         }
190       break;
191     case GCONF_VALUE_FLOAT:
192       gconf_value_set_float(gval, value->_u.float_value);
193       break;
194     case GCONF_VALUE_BOOL:
195       gconf_value_set_bool(gval, value->_u.bool_value);
196       break;
197     case GCONF_VALUE_SCHEMA:
198       gconf_value_set_schema_nocopy(gval,
199                                     gconf_schema_from_corba_schema(&(value->_u.schema_value)));
200       break;
201     case GCONF_VALUE_LIST:
202       {
203         GSList* list = NULL;
204         guint i = 0;
205 
206         switch (value->_u.list_value.list_type)
207           {
208           case BIntVal:
209             gconf_value_set_list_type(gval, GCONF_VALUE_INT);
210             break;
211           case BBoolVal:
212             gconf_value_set_list_type(gval, GCONF_VALUE_BOOL);
213             break;
214           case BFloatVal:
215             gconf_value_set_list_type(gval, GCONF_VALUE_FLOAT);
216             break;
217           case BStringVal:
218             gconf_value_set_list_type(gval, GCONF_VALUE_STRING);
219             break;
220           case BInvalidVal:
221             break;
222           default:
223             g_warning("Bizarre list type in %s", G_STRFUNC);
224             break;
225           }
226 
227         if (gconf_value_get_list_type(gval) != GCONF_VALUE_INVALID)
228           {
229             i = 0;
230             while (i < value->_u.list_value.seq._length)
231               {
232                 GConfValue* val;
233 
234                 /* This is a bit dubious; we cast a ConfigBasicValue to ConfigValue
235                    because they have the same initial members, but by the time
236                    the CORBA and C specs kick in, not sure we are guaranteed
237                    to be able to do this.
238                 */
239                 val = gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[i]);
240 
241                 if (val == NULL)
242                   gconf_log(GCL_ERR, _("Couldn't interpret CORBA value for list element"));
243                 else if (val->type != gconf_value_get_list_type(gval))
244                   gconf_log(GCL_ERR, _("Incorrect type for list element in %s"), G_STRFUNC);
245                 else
246                   list = g_slist_prepend(list, val);
247 
248                 ++i;
249               }
250 
251             list = g_slist_reverse(list);
252 
253             gconf_value_set_list_nocopy(gval, list);
254           }
255         else
256           {
257             gconf_log(GCL_ERR, _("Received list from gconfd with a bad list type"));
258           }
259       }
260       break;
261     case GCONF_VALUE_PAIR:
262       {
263         g_return_val_if_fail(value->_u.pair_value._length == 2, gval);
264 
265         gconf_value_set_car_nocopy(gval,
266                                    gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[0]));
267 
268         gconf_value_set_cdr_nocopy(gval,
269                                    gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[1]));
270       }
271       break;
272     default:
273       g_assert_not_reached();
274       break;
275     }
276 
277   return gval;
278 }
279 
280 void
gconf_fill_corba_value_from_gconf_value(const GConfValue * value,ConfigValue * cv)281 gconf_fill_corba_value_from_gconf_value(const GConfValue *value,
282                                         ConfigValue      *cv)
283 {
284   if (value == NULL)
285     {
286       cv->_d = InvalidVal;
287       return;
288     }
289 
290   switch (value->type)
291     {
292     case GCONF_VALUE_INT:
293       cv->_d = IntVal;
294       cv->_u.int_value = gconf_value_get_int(value);
295       break;
296     case GCONF_VALUE_STRING:
297       cv->_d = StringVal;
298       cv->_u.string_value = CORBA_string_dup((char*)gconf_value_get_string(value));
299       break;
300     case GCONF_VALUE_FLOAT:
301       cv->_d = FloatVal;
302       cv->_u.float_value = gconf_value_get_float(value);
303       break;
304     case GCONF_VALUE_BOOL:
305       cv->_d = BoolVal;
306       cv->_u.bool_value = gconf_value_get_bool(value);
307       break;
308     case GCONF_VALUE_SCHEMA:
309       cv->_d = SchemaVal;
310       gconf_fill_corba_schema_from_gconf_schema (gconf_value_get_schema(value),
311                                                  &cv->_u.schema_value);
312       break;
313     case GCONF_VALUE_LIST:
314       {
315         guint n, i;
316         GSList* list;
317 
318         cv->_d = ListVal;
319 
320         list = gconf_value_get_list(value);
321 
322         n = g_slist_length(list);
323 
324         cv->_u.list_value.seq._buffer =
325           CORBA_sequence_ConfigBasicValue_allocbuf(n);
326         cv->_u.list_value.seq._length = n;
327         cv->_u.list_value.seq._maximum = n;
328         CORBA_sequence_set_release(&cv->_u.list_value.seq, TRUE);
329 
330         switch (gconf_value_get_list_type(value))
331           {
332           case GCONF_VALUE_INT:
333             cv->_u.list_value.list_type = BIntVal;
334             break;
335 
336           case GCONF_VALUE_BOOL:
337             cv->_u.list_value.list_type = BBoolVal;
338             break;
339 
340           case GCONF_VALUE_STRING:
341             cv->_u.list_value.list_type = BStringVal;
342             break;
343 
344           case GCONF_VALUE_FLOAT:
345             cv->_u.list_value.list_type = BFloatVal;
346             break;
347 
348           case GCONF_VALUE_SCHEMA:
349             cv->_u.list_value.list_type = BSchemaVal;
350             break;
351 
352           default:
353             cv->_u.list_value.list_type = BInvalidVal;
354             gconf_log(GCL_DEBUG, "Invalid list type in %s", G_STRFUNC);
355             break;
356           }
357 
358         i= 0;
359         while (list != NULL)
360           {
361             /* That dubious ConfigBasicValue->ConfigValue cast again */
362             gconf_fill_corba_value_from_gconf_value((GConfValue*)list->data,
363                                                     (ConfigValue*)&cv->_u.list_value.seq._buffer[i]);
364 
365             list = g_slist_next(list);
366             ++i;
367           }
368       }
369       break;
370     case GCONF_VALUE_PAIR:
371       {
372         cv->_d = PairVal;
373 
374         cv->_u.pair_value._buffer =
375           CORBA_sequence_ConfigBasicValue_allocbuf(2);
376         cv->_u.pair_value._length = 2;
377         cv->_u.pair_value._maximum = 2;
378         CORBA_sequence_set_release(&cv->_u.pair_value, TRUE);
379 
380         /* dubious cast */
381         gconf_fill_corba_value_from_gconf_value (gconf_value_get_car(value),
382                                                  (ConfigValue*)&cv->_u.pair_value._buffer[0]);
383         gconf_fill_corba_value_from_gconf_value(gconf_value_get_cdr(value),
384                                                 (ConfigValue*)&cv->_u.pair_value._buffer[1]);
385       }
386       break;
387 
388     case GCONF_VALUE_INVALID:
389       cv->_d = InvalidVal;
390       break;
391     default:
392       cv->_d = InvalidVal;
393       gconf_log(GCL_DEBUG, "Unknown type in %s", G_STRFUNC);
394       break;
395     }
396 }
397 
398 ConfigValue*
gconf_corba_value_from_gconf_value(const GConfValue * value)399 gconf_corba_value_from_gconf_value (const GConfValue* value)
400 {
401   ConfigValue* cv;
402 
403   cv = ConfigValue__alloc();
404 
405   gconf_fill_corba_value_from_gconf_value(value, cv);
406 
407   return cv;
408 }
409 
410 ConfigValue*
gconf_invalid_corba_value(void)411 gconf_invalid_corba_value (void)
412 {
413   ConfigValue* cv;
414 
415   cv = ConfigValue__alloc();
416 
417   cv->_d = InvalidVal;
418 
419   return cv;
420 }
421 
422 gchar*
gconf_object_to_string(CORBA_Object obj,GError ** err)423 gconf_object_to_string (CORBA_Object obj,
424                         GError **err)
425 {
426   CORBA_Environment ev;
427   gchar *ior;
428   gchar *retval;
429 
430   CORBA_exception_init (&ev);
431 
432   ior = CORBA_ORB_object_to_string (gconf_orb_get (), obj, &ev);
433 
434   if (ior == NULL)
435     {
436       gconf_set_error (err,
437                        GCONF_ERROR_FAILED,
438                        _("Failed to convert object to IOR"));
439 
440       return NULL;
441     }
442 
443   retval = g_strdup (ior);
444 
445   CORBA_free (ior);
446 
447   return retval;
448 }
449 
450 static ConfigValueType
corba_type_from_gconf_type(GConfValueType type)451 corba_type_from_gconf_type(GConfValueType type)
452 {
453   switch (type)
454     {
455     case GCONF_VALUE_INT:
456       return IntVal;
457     case GCONF_VALUE_BOOL:
458       return BoolVal;
459     case GCONF_VALUE_FLOAT:
460       return FloatVal;
461     case GCONF_VALUE_INVALID:
462       return InvalidVal;
463     case GCONF_VALUE_STRING:
464       return StringVal;
465     case GCONF_VALUE_SCHEMA:
466       return SchemaVal;
467     case GCONF_VALUE_LIST:
468       return ListVal;
469     case GCONF_VALUE_PAIR:
470       return PairVal;
471     default:
472       g_assert_not_reached();
473       return InvalidVal;
474     }
475 }
476 
477 static GConfValueType
gconf_type_from_corba_type(ConfigValueType type)478 gconf_type_from_corba_type(ConfigValueType type)
479 {
480   switch (type)
481     {
482     case InvalidVal:
483       return GCONF_VALUE_INVALID;
484     case StringVal:
485       return GCONF_VALUE_STRING;
486     case IntVal:
487       return GCONF_VALUE_INT;
488     case FloatVal:
489       return GCONF_VALUE_FLOAT;
490     case SchemaVal:
491       return GCONF_VALUE_SCHEMA;
492     case BoolVal:
493       return GCONF_VALUE_BOOL;
494     case ListVal:
495       return GCONF_VALUE_LIST;
496     case PairVal:
497       return GCONF_VALUE_PAIR;
498     default:
499       g_assert_not_reached();
500       return GCONF_VALUE_INVALID;
501     }
502 }
503 
504 void
gconf_fill_corba_schema_from_gconf_schema(const GConfSchema * sc,ConfigSchema * cs)505 gconf_fill_corba_schema_from_gconf_schema(const GConfSchema *sc,
506                                           ConfigSchema      *cs)
507 {
508   cs->value_type = corba_type_from_gconf_type (gconf_schema_get_type (sc));
509   cs->value_list_type = corba_type_from_gconf_type (gconf_schema_get_list_type (sc));
510   cs->value_car_type = corba_type_from_gconf_type (gconf_schema_get_car_type (sc));
511   cs->value_cdr_type = corba_type_from_gconf_type (gconf_schema_get_cdr_type (sc));
512 
513   cs->locale = CORBA_string_dup (gconf_schema_get_locale (sc) ? gconf_schema_get_locale (sc) : "");
514   cs->short_desc = CORBA_string_dup (gconf_schema_get_short_desc (sc) ? gconf_schema_get_short_desc (sc) : "");
515   cs->long_desc = CORBA_string_dup (gconf_schema_get_long_desc (sc) ? gconf_schema_get_long_desc (sc) : "");
516   cs->owner = CORBA_string_dup (gconf_schema_get_owner (sc) ? gconf_schema_get_owner (sc) : "");
517 
518   {
519     gchar* encoded;
520     GConfValue* default_val;
521 
522     default_val = gconf_schema_get_default_value (sc);
523 
524     if (default_val)
525       {
526         encoded = gconf_value_encode (default_val);
527 
528         g_assert (encoded != NULL);
529 
530         cs->encoded_default_value = CORBA_string_dup (encoded);
531 
532         g_free (encoded);
533       }
534     else
535       cs->encoded_default_value = CORBA_string_dup ("");
536   }
537 }
538 
539 ConfigSchema*
gconf_corba_schema_from_gconf_schema(const GConfSchema * sc)540 gconf_corba_schema_from_gconf_schema (const GConfSchema* sc)
541 {
542   ConfigSchema* cs;
543 
544   cs = ConfigSchema__alloc ();
545 
546   gconf_fill_corba_schema_from_gconf_schema (sc, cs);
547 
548   return cs;
549 }
550 
551 GConfSchema*
gconf_schema_from_corba_schema(const ConfigSchema * cs)552 gconf_schema_from_corba_schema(const ConfigSchema* cs)
553 {
554   GConfSchema* sc;
555   GConfValueType type = GCONF_VALUE_INVALID;
556   GConfValueType list_type = GCONF_VALUE_INVALID;
557   GConfValueType car_type = GCONF_VALUE_INVALID;
558   GConfValueType cdr_type = GCONF_VALUE_INVALID;
559 
560   type = gconf_type_from_corba_type(cs->value_type);
561   list_type = gconf_type_from_corba_type(cs->value_list_type);
562   car_type = gconf_type_from_corba_type(cs->value_car_type);
563   cdr_type = gconf_type_from_corba_type(cs->value_cdr_type);
564 
565   sc = gconf_schema_new();
566 
567   gconf_schema_set_type(sc, type);
568   gconf_schema_set_list_type(sc, list_type);
569   gconf_schema_set_car_type(sc, car_type);
570   gconf_schema_set_cdr_type(sc, cdr_type);
571 
572   if (*cs->locale != '\0')
573     {
574       if (!g_utf8_validate (cs->locale, -1, NULL))
575         gconf_log (GCL_ERR, _("Invalid UTF-8 in locale for schema"));
576       else
577         gconf_schema_set_locale(sc, cs->locale);
578     }
579 
580   if (*cs->short_desc != '\0')
581     {
582       if (!g_utf8_validate (cs->short_desc, -1, NULL))
583         gconf_log (GCL_ERR, _("Invalid UTF-8 in short description for schema"));
584       else
585         gconf_schema_set_short_desc(sc, cs->short_desc);
586     }
587 
588   if (*cs->long_desc != '\0')
589     {
590       if (!g_utf8_validate (cs->long_desc, -1, NULL))
591         gconf_log (GCL_ERR, _("Invalid UTF-8 in long description for schema"));
592       else
593         gconf_schema_set_long_desc(sc, cs->long_desc);
594     }
595 
596   if (*cs->owner != '\0')
597     {
598       if (!g_utf8_validate (cs->owner, -1, NULL))
599         gconf_log (GCL_ERR, _("Invalid UTF-8 in owner for schema"));
600       else
601         gconf_schema_set_owner(sc, cs->owner);
602     }
603 
604   {
605     GConfValue* val;
606 
607     val = gconf_value_decode(cs->encoded_default_value);
608 
609     if (val)
610       gconf_schema_set_default_value_nocopy(sc, val);
611   }
612 
613   return sc;
614 }
615 #endif /* HAVE_CORBA */
616 
617 const gchar*
gconf_value_type_to_string(GConfValueType type)618 gconf_value_type_to_string(GConfValueType type)
619 {
620   switch (type)
621     {
622     case GCONF_VALUE_INT:
623       return "int";
624     case GCONF_VALUE_STRING:
625       return "string";
626     case GCONF_VALUE_FLOAT:
627       return "float";
628     case GCONF_VALUE_BOOL:
629       return "bool";
630     case GCONF_VALUE_SCHEMA:
631       return "schema";
632     case GCONF_VALUE_LIST:
633       return "list";
634     case GCONF_VALUE_PAIR:
635       return "pair";
636     case GCONF_VALUE_INVALID:
637       return "*invalid*";
638     default:
639       g_assert_not_reached();
640       return NULL; /* for warnings */
641     }
642 }
643 
644 GConfValueType
gconf_value_type_from_string(const gchar * type_str)645 gconf_value_type_from_string(const gchar* type_str)
646 {
647   if (strcmp(type_str, "int") == 0)
648     return GCONF_VALUE_INT;
649   else if (strcmp(type_str, "float") == 0)
650     return GCONF_VALUE_FLOAT;
651   else if (strcmp(type_str, "string") == 0)
652     return GCONF_VALUE_STRING;
653   else if (strcmp(type_str, "bool") == 0)
654     return GCONF_VALUE_BOOL;
655   else if (strcmp(type_str, "schema") == 0)
656     return GCONF_VALUE_SCHEMA;
657   else if (strcmp(type_str, "list") == 0)
658     return GCONF_VALUE_LIST;
659   else if (strcmp(type_str, "pair") == 0)
660     return GCONF_VALUE_PAIR;
661   else
662     return GCONF_VALUE_INVALID;
663 }
664 
665 /*
666  * Configuration files (yikes! we can't store our configuration in GConf!)
667  */
668 
669 static gchar*
unquote_string(gchar * s)670 unquote_string(gchar* s)
671 {
672   gchar* end;
673 
674   /* Strip whitespace and first quote from front of string */
675   while (*s && (g_ascii_isspace(*s) || (*s == '"')))
676     ++s;
677 
678   end = s;
679   while (*end)
680     ++end;
681 
682   --end; /* one back from '\0' */
683 
684   /* Strip whitespace and last quote from end of string */
685   while ((end > s) && (g_ascii_isspace(*end) || (*end == '"')))
686     {
687       *end = '\0';
688       --end;
689     }
690 
691   return s;
692 }
693 
694 #ifdef G_OS_WIN32
695 
696 /* Return the home directory with forward slashes instead of backslashes */
697 
698 const char*
_gconf_win32_get_home_dir(void)699 _gconf_win32_get_home_dir (void)
700 {
701   static GQuark quark = 0;
702   char *home_copy, *p;
703 
704   if (quark != 0)
705     return g_quark_to_string (quark);
706 
707   home_copy = g_strdup (g_get_home_dir ());
708 
709   /* Replace backslashes with forward slashes */
710   for (p = home_copy; *p; p++)
711     if (*p == '\\')
712       *p = '/';
713 
714   quark = g_quark_from_string (home_copy);
715   g_free (home_copy);
716 
717   return g_quark_to_string (quark);
718 }
719 
720 #endif
721 
722 static const gchar *
get_user_source_dir(void)723 get_user_source_dir (void)
724 {
725   static const gchar *user_source = NULL;
726 
727   if (user_source == NULL)
728     {
729       gchar *path_new;
730       gchar *path_old;
731 
732       path_new = g_build_filename (g_get_user_config_dir (), "gconf", NULL);
733 #ifndef G_OS_WIN32
734       path_old = g_build_filename (g_get_home_dir (), ".gconf", NULL);
735 #else
736       path_old = g_build_filename (_gconf_win32_get_home_dir (), ".gconf", NULL);
737 #endif
738       if ((g_file_test (path_new, G_FILE_TEST_IS_DIR))
739           || (! g_file_test (path_old, G_FILE_TEST_IS_DIR)))
740         {
741           user_source = path_new;
742           g_free (path_old);
743         }
744       else
745         {
746           g_free (path_new);
747           user_source = path_old;
748         }
749     }
750 
751   return user_source;
752 }
753 
754 static const gchar*
get_variable(const gchar * varname)755 get_variable(const gchar* varname)
756 {
757   /* These first two DO NOT use environment variables, which
758      makes things a bit more "secure" in some sense
759   */
760   if (strcmp(varname, "HOME") == 0)
761     {
762 #ifndef G_OS_WIN32
763       return g_get_home_dir ();
764 #else
765       return _gconf_win32_get_home_dir ();
766 #endif
767     }
768   else if (strcmp(varname, "USERCONFIGDIR") == 0)
769     {
770       return g_get_user_config_dir();
771     }
772   else if (strcmp(varname, "DEFAULTUSERSOURCE") == 0)
773     {
774       return get_user_source_dir();
775     }
776   else if (strcmp(varname, "USER") == 0)
777     {
778       return g_get_user_name();
779     }
780   else if (varname[0] == 'E' &&
781            varname[1] == 'N' &&
782            varname[2] == 'V' &&
783            varname[3] == '_')
784     {
785       /* This is magic: if a variable called ENV_FOO is used,
786          then the environment variable FOO is checked */
787       const gchar* envvar = g_getenv(&varname[4]);
788 
789       if (envvar)
790         return envvar;
791       else
792         return "";
793     }
794   else
795     return "";
796 }
797 
798 static gchar*
subst_variables(const gchar * src)799 subst_variables(const gchar* src)
800 {
801   const gchar* iter;
802   gchar* retval;
803   guint retval_len;
804   guint pos;
805 
806   g_return_val_if_fail(src != NULL, NULL);
807 
808   retval_len = strlen(src) + 1;
809   pos = 0;
810 
811   retval = g_malloc0(retval_len+3); /* add 3 just to avoid off-by-one
812                                        segvs - yeah I know it bugs
813                                        you, but C sucks */
814 
815   iter = src;
816 
817   while (*iter)
818     {
819       gboolean performed_subst = FALSE;
820 
821       if (pos >= retval_len)
822         {
823           retval_len *= 2;
824           retval = g_realloc(retval, retval_len+3); /* add 3 for luck */
825         }
826 
827       if (*iter == '$' && *(iter+1) == '(')
828         {
829           const gchar* varstart = iter + 2;
830           const gchar* varend   = strchr(varstart, ')');
831 
832           if (varend != NULL)
833             {
834               char* varname;
835               const gchar* varval;
836               guint varval_len;
837 
838               performed_subst = TRUE;
839 
840               varname = g_strndup(varstart, varend - varstart);
841 
842               varval = get_variable(varname);
843               g_free(varname);
844 
845               varval_len = strlen(varval);
846 
847               if ((retval_len - pos) < varval_len)
848                 {
849                   retval_len = pos + varval_len;
850                   retval = g_realloc(retval, retval_len+3);
851                 }
852 
853               strcpy(&retval[pos], varval);
854               pos += varval_len;
855 
856               iter = varend + 1;
857             }
858         }
859 
860       if (!performed_subst)
861         {
862           retval[pos] = *iter;
863           ++pos;
864           ++iter;
865         }
866     }
867   retval[pos] = '\0';
868 
869   return retval;
870 }
871 
872 GSList *
gconf_load_source_path(const gchar * filename,GError ** err)873 gconf_load_source_path(const gchar* filename, GError** err)
874 {
875   FILE* f;
876   GSList *l = NULL;
877   gchar buf[512];
878 
879   f = g_fopen(filename, "r");
880 
881   if (f == NULL)
882     {
883       if (err)
884         *err = gconf_error_new(GCONF_ERROR_FAILED,
885                                _("Couldn't open path file `%s': %s\n"),
886                                filename,
887                                g_strerror(errno));
888       return NULL;
889     }
890 
891   while (fgets(buf, 512, f) != NULL)
892     {
893       gchar* s = buf;
894 
895       while (*s && g_ascii_isspace(*s))
896         ++s;
897 
898       if (*s == '#')
899         {
900           /* Allow comments, why not */
901         }
902       else if (*s == '\0')
903         {
904           /* Blank line */
905         }
906       else if (strncmp("include", s, 7) == 0)
907         {
908           gchar* unq;
909           GSList* included;
910           gchar *varsubst;
911 
912           s += 7;
913           while (g_ascii_isspace(*s))
914             s++;
915           unq = unquote_string(s);
916 
917           varsubst = subst_variables (unq);
918 #ifdef G_OS_WIN32
919 	  {
920 	    gchar *tem = varsubst;
921 	    varsubst = _gconf_win32_replace_prefix (varsubst);
922 	    g_free (tem);
923 	  }
924 #endif
925           included = gconf_load_source_path (varsubst, NULL);
926           g_free (varsubst);
927 
928           if (included != NULL)
929             l = g_slist_concat (l, included);
930         }
931       else
932         {
933           gchar* unq;
934           gchar* varsubst;
935 
936           unq = unquote_string(buf);
937           varsubst = subst_variables(unq);
938 
939           if (*varsubst != '\0') /* Drop lines with just two quote marks or something */
940             {
941               gconf_log(GCL_DEBUG, _("Adding source `%s'\n"), varsubst);
942               l = g_slist_append (l, varsubst);
943             }
944 	  else
945 	    {
946 	      g_free (varsubst);
947 	    }
948         }
949     }
950 
951   if (ferror(f))
952     {
953       /* This should basically never happen */
954       if (err)
955         *err = gconf_error_new(GCONF_ERROR_FAILED,
956                                _("Read error on file `%s': %s\n"),
957                                filename,
958                                g_strerror(errno));
959       /* don't return, we want to go ahead and return any
960          addresses we already loaded. */
961     }
962 
963   fclose(f);
964 
965   return l;
966 }
967 
968 char *
gconf_address_list_get_persistent_name(GSList * addresses)969 gconf_address_list_get_persistent_name (GSList *addresses)
970 {
971   GSList  *tmp;
972   GString *str = NULL;
973 
974   if (!addresses)
975     {
976       return g_strdup ("empty");
977     }
978 
979   tmp = addresses;
980   while (tmp != NULL)
981     {
982       const char *address = tmp->data;
983 
984       if (str == NULL)
985 	{
986 	  str = g_string_new (address);
987 	}
988       else
989         {
990           g_string_append_c (str, GCONF_DATABASE_LIST_DELIM);
991           g_string_append (str, address);
992         }
993 
994       tmp = tmp->next;
995     }
996 
997   return g_string_free (str, FALSE);
998 }
999 
1000 GSList *
gconf_persistent_name_get_address_list(const char * persistent_name)1001 gconf_persistent_name_get_address_list (const char *persistent_name)
1002 {
1003   char   delim [2] = { GCONF_DATABASE_LIST_DELIM, '\0' };
1004   char **address_vector;
1005 
1006   address_vector = g_strsplit (persistent_name, delim, -1);
1007   if (address_vector != NULL)
1008     {
1009       GSList  *retval = NULL;
1010       int      i;
1011 
1012       i = 0;
1013       while (address_vector [i] != NULL)
1014         {
1015           retval = g_slist_append (retval, g_strdup (address_vector [i]));
1016           ++i;
1017         }
1018 
1019       g_strfreev (address_vector);
1020 
1021       return retval;
1022     }
1023   else
1024     {
1025       return g_slist_append (NULL, g_strdup (persistent_name));
1026     }
1027 }
1028 
1029 void
gconf_address_list_free(GSList * addresses)1030 gconf_address_list_free (GSList *addresses)
1031 {
1032   GSList *tmp;
1033 
1034   tmp = addresses;
1035   while (tmp != NULL)
1036     {
1037       g_free (tmp->data);
1038       tmp = tmp->next;
1039     }
1040 
1041   g_slist_free (addresses);
1042 }
1043 
1044 /* This should also support concatting filesystem dirs and keys,
1045    or dir and subdir.
1046 */
1047 gchar*
gconf_concat_dir_and_key(const gchar * dir,const gchar * key)1048 gconf_concat_dir_and_key(const gchar* dir, const gchar* key)
1049 {
1050   guint dirlen;
1051   guint keylen;
1052   gchar* retval;
1053 
1054   g_return_val_if_fail(dir != NULL, NULL);
1055   g_return_val_if_fail(key != NULL, NULL);
1056   g_return_val_if_fail(*dir == '/', NULL);
1057 
1058   dirlen = strlen(dir);
1059   keylen = strlen(key);
1060 
1061   retval = g_malloc0(dirlen+keylen+3); /* auto-null-terminate */
1062 
1063   strcpy(retval, dir);
1064 
1065   if (dir[dirlen-1] == '/')
1066     {
1067       /* dir ends in slash, strip key slash if needed */
1068       if (*key == '/')
1069         ++key;
1070 
1071       strcpy((retval+dirlen), key);
1072     }
1073   else
1074     {
1075       /* Dir doesn't end in slash, add slash if key lacks one. */
1076       gchar* dest = retval + dirlen;
1077 
1078       if (*key != '/')
1079         {
1080           *dest = '/';
1081           ++dest;
1082         }
1083 
1084       strcpy(dest, key);
1085     }
1086 
1087   return retval;
1088 }
1089 
1090 gulong
gconf_string_to_gulong(const gchar * str)1091 gconf_string_to_gulong(const gchar* str)
1092 {
1093   gulong retval;
1094   gchar *end;
1095   errno = 0;
1096   retval = strtoul(str, &end, 10);
1097   if (end == str || errno != 0)
1098     retval = 0;
1099 
1100   return retval;
1101 }
1102 
1103 gboolean
gconf_string_to_double(const gchar * str,gdouble * retloc)1104 gconf_string_to_double(const gchar* str,
1105                        gdouble*     retloc)
1106 {
1107   char *end;
1108 
1109   errno = 0;
1110   *retloc = g_ascii_strtod (str, &end);
1111   if (end == str || errno != 0)
1112     {
1113       *retloc = 0.0;
1114       return FALSE;
1115     }
1116   else
1117     return TRUE;
1118 }
1119 
1120 gchar*
gconf_double_to_string(gdouble val)1121 gconf_double_to_string (gdouble val)
1122 {
1123   char str[G_ASCII_DTOSTR_BUF_SIZE];
1124 
1125   g_ascii_dtostr (str, G_ASCII_DTOSTR_BUF_SIZE, val);
1126 
1127   return g_strdup (str);
1128 }
1129 
1130 const gchar*
gconf_current_locale(void)1131 gconf_current_locale(void)
1132 {
1133 #ifdef HAVE_LC_MESSAGES
1134   return setlocale(LC_MESSAGES, NULL);
1135 #else
1136   return setlocale(LC_CTYPE, NULL);
1137 #endif
1138 }
1139 
1140 /*
1141  * Log
1142  */
1143 
1144 void
gconf_log(GConfLogPriority pri,const gchar * fmt,...)1145 gconf_log(GConfLogPriority pri, const gchar* fmt, ...)
1146 {
1147   va_list args;
1148   GLogLevelFlags loglevel;
1149 
1150   if (!gconf_log_debug_messages &&
1151       pri == GCL_DEBUG)
1152     return;
1153 
1154   switch (pri)
1155     {
1156     case GCL_EMERG:
1157     case GCL_ALERT:
1158     case GCL_CRIT:
1159       loglevel = G_LOG_LEVEL_ERROR;
1160       break;
1161     case GCL_ERR:
1162       loglevel = G_LOG_LEVEL_CRITICAL;
1163       break;
1164     case GCL_WARNING:
1165       loglevel = G_LOG_LEVEL_WARNING;
1166       break;
1167     case GCL_NOTICE:
1168       loglevel = G_LOG_LEVEL_MESSAGE;
1169       break;
1170     case GCL_INFO:
1171       loglevel = G_LOG_LEVEL_INFO;
1172       break;
1173     case GCL_DEBUG:
1174       loglevel = G_LOG_LEVEL_DEBUG;
1175       break;
1176     default:
1177       g_assert_not_reached();
1178       break;
1179     }
1180 
1181   va_start (args, fmt);
1182   g_logv (G_LOG_DOMAIN, loglevel, fmt, args);
1183   va_end (args);
1184 }
1185 
1186 /*
1187  * List/pair conversion
1188  */
1189 
1190 GConfValue*
gconf_value_list_from_primitive_list(GConfValueType list_type,GSList * list,GError ** err)1191 gconf_value_list_from_primitive_list(GConfValueType list_type, GSList* list,
1192                                      GError **err)
1193 {
1194   GSList* value_list;
1195   GSList* tmp;
1196 
1197   g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, NULL);
1198   g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
1199   g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
1200 
1201   value_list = NULL;
1202 
1203   tmp = list;
1204 
1205   while (tmp != NULL)
1206     {
1207       GConfValue* val;
1208 
1209       val = gconf_value_new(list_type);
1210 
1211       switch (list_type)
1212         {
1213         case GCONF_VALUE_INT:
1214           gconf_value_set_int(val, GPOINTER_TO_INT(tmp->data));
1215           break;
1216 
1217         case GCONF_VALUE_BOOL:
1218           gconf_value_set_bool(val, GPOINTER_TO_INT(tmp->data));
1219           break;
1220 
1221         case GCONF_VALUE_FLOAT:
1222           gconf_value_set_float(val, *((gdouble*)tmp->data));
1223           break;
1224 
1225         case GCONF_VALUE_STRING:
1226           if (!g_utf8_validate (tmp->data, -1, NULL))
1227             {
1228               g_set_error (err, GCONF_ERROR,
1229                            GCONF_ERROR_FAILED,
1230                            _("Text contains invalid UTF-8"));
1231               goto error;
1232             }
1233 
1234           gconf_value_set_string(val, tmp->data);
1235           break;
1236 
1237         case GCONF_VALUE_SCHEMA:
1238           if (!gconf_schema_validate (tmp->data, err))
1239             goto error;
1240           gconf_value_set_schema(val, tmp->data);
1241           break;
1242 
1243         default:
1244           g_assert_not_reached();
1245           break;
1246         }
1247 
1248       value_list = g_slist_prepend(value_list, val);
1249 
1250       tmp = g_slist_next(tmp);
1251     }
1252 
1253   /* Get it in the right order. */
1254   value_list = g_slist_reverse(value_list);
1255 
1256   {
1257     GConfValue* value_with_list;
1258 
1259     value_with_list = gconf_value_new(GCONF_VALUE_LIST);
1260     gconf_value_set_list_type(value_with_list, list_type);
1261     gconf_value_set_list_nocopy(value_with_list, value_list);
1262 
1263     return value_with_list;
1264   }
1265 
1266  error:
1267   g_slist_foreach (value_list, (GFunc)gconf_value_free, NULL);
1268   g_slist_free (value_list);
1269   return NULL;
1270 }
1271 
1272 
1273 static GConfValue*
from_primitive(GConfValueType type,gconstpointer address,GError ** err)1274 from_primitive(GConfValueType type, gconstpointer address,
1275                GError **err)
1276 {
1277   GConfValue* val;
1278 
1279   val = gconf_value_new(type);
1280 
1281   switch (type)
1282     {
1283     case GCONF_VALUE_INT:
1284       gconf_value_set_int(val, *((const gint*)address));
1285       break;
1286 
1287     case GCONF_VALUE_BOOL:
1288       gconf_value_set_bool(val, *((const gboolean*)address));
1289       break;
1290 
1291     case GCONF_VALUE_STRING:
1292       if (!g_utf8_validate (*((const gchar**)address), -1, NULL))
1293         {
1294           g_set_error (err, GCONF_ERROR,
1295                        GCONF_ERROR_FAILED,
1296                        _("Text contains invalid UTF-8"));
1297           gconf_value_free (val);
1298           return NULL;
1299         }
1300 
1301       gconf_value_set_string(val, *((const gchar**)address));
1302       break;
1303 
1304     case GCONF_VALUE_FLOAT:
1305       gconf_value_set_float(val, *((const gdouble*)address));
1306       break;
1307 
1308     case GCONF_VALUE_SCHEMA:
1309       if (!gconf_schema_validate (*((GConfSchema**)address), err))
1310         {
1311           gconf_value_free (val);
1312           return NULL;
1313         }
1314 
1315       gconf_value_set_schema(val, *((GConfSchema**)address));
1316       break;
1317 
1318     default:
1319       g_assert_not_reached();
1320       break;
1321     }
1322 
1323   return val;
1324 }
1325 
1326 GConfValue*
gconf_value_pair_from_primitive_pair(GConfValueType car_type,GConfValueType cdr_type,gconstpointer address_of_car,gconstpointer address_of_cdr,GError ** err)1327 gconf_value_pair_from_primitive_pair(GConfValueType car_type,
1328                                      GConfValueType cdr_type,
1329                                      gconstpointer address_of_car,
1330                                      gconstpointer address_of_cdr,
1331                                      GError       **err)
1332 {
1333   GConfValue* pair;
1334   GConfValue* car;
1335   GConfValue* cdr;
1336 
1337   g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, NULL);
1338   g_return_val_if_fail(car_type != GCONF_VALUE_LIST, NULL);
1339   g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, NULL);
1340   g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, NULL);
1341   g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, NULL);
1342   g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, NULL);
1343   g_return_val_if_fail(address_of_car != NULL, NULL);
1344   g_return_val_if_fail(address_of_cdr != NULL, NULL);
1345 
1346   car = from_primitive(car_type, address_of_car, err);
1347   if (car == NULL)
1348     return NULL;
1349   cdr = from_primitive(cdr_type, address_of_cdr, err);
1350   if (cdr == NULL)
1351     {
1352       gconf_value_free (car);
1353       return NULL;
1354     }
1355 
1356   pair = gconf_value_new(GCONF_VALUE_PAIR);
1357   gconf_value_set_car_nocopy(pair, car);
1358   gconf_value_set_cdr_nocopy(pair, cdr);
1359 
1360   return pair;
1361 }
1362 
1363 
1364 GSList*
gconf_value_list_to_primitive_list_destructive(GConfValue * val,GConfValueType list_type,GError ** err)1365 gconf_value_list_to_primitive_list_destructive(GConfValue* val,
1366                                                GConfValueType list_type,
1367                                                GError** err)
1368 {
1369   GSList* retval;
1370 
1371   g_return_val_if_fail(val != NULL, NULL);
1372   g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, NULL);
1373   g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
1374   g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
1375   g_return_val_if_fail(err == NULL || *err == NULL, NULL);
1376 
1377   if (val->type != GCONF_VALUE_LIST)
1378     {
1379       if (err)
1380         *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1381                                _("Expected list, got %s"),
1382                                gconf_value_type_to_string(val->type));
1383       gconf_value_free(val);
1384       return NULL;
1385     }
1386 
1387   if (gconf_value_get_list_type(val) != list_type)
1388     {
1389       if (err)
1390         *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1391                                _("Expected list of %s, got list of %s"),
1392                                gconf_value_type_to_string(list_type),
1393                                gconf_value_type_to_string(gconf_value_get_list_type (val)));
1394       gconf_value_free(val);
1395       return NULL;
1396     }
1397 
1398   g_assert(gconf_value_get_list_type(val) == list_type);
1399 
1400   retval = gconf_value_steal_list (val);
1401 
1402   gconf_value_free (val);
1403   val = NULL;
1404 
1405   {
1406     /* map (typeChange, retval) */
1407     GSList* tmp;
1408 
1409     tmp = retval;
1410 
1411     while (tmp != NULL)
1412       {
1413         GConfValue* elem = tmp->data;
1414 
1415         g_assert(elem != NULL);
1416         g_assert(elem->type == list_type);
1417 
1418         switch (list_type)
1419           {
1420           case GCONF_VALUE_INT:
1421             tmp->data = GINT_TO_POINTER(gconf_value_get_int(elem));
1422             break;
1423 
1424           case GCONF_VALUE_BOOL:
1425             tmp->data = GINT_TO_POINTER(gconf_value_get_bool(elem));
1426             break;
1427 
1428           case GCONF_VALUE_FLOAT:
1429             {
1430               gdouble* d = g_new(gdouble, 1);
1431               *d = gconf_value_get_float(elem);
1432               tmp->data = d;
1433             }
1434             break;
1435 
1436           case GCONF_VALUE_STRING:
1437             tmp->data = gconf_value_steal_string (elem);
1438             break;
1439 
1440           case GCONF_VALUE_SCHEMA:
1441             tmp->data = gconf_value_steal_schema (elem);
1442             break;
1443 
1444           default:
1445             g_assert_not_reached();
1446             break;
1447           }
1448 
1449         /* Clean up the value */
1450         gconf_value_free(elem);
1451 
1452         tmp = g_slist_next(tmp);
1453       }
1454   } /* list conversion block */
1455 
1456   return retval;
1457 }
1458 
1459 
1460 static void
primitive_value(gpointer retloc,GConfValue * val)1461 primitive_value(gpointer retloc, GConfValue* val)
1462 {
1463   switch (val->type)
1464     {
1465     case GCONF_VALUE_INT:
1466       *((gint*)retloc) = gconf_value_get_int(val);
1467       break;
1468 
1469     case GCONF_VALUE_FLOAT:
1470       *((gdouble*)retloc) = gconf_value_get_float(val);
1471       break;
1472 
1473     case GCONF_VALUE_STRING:
1474       {
1475         *((gchar**)retloc) = gconf_value_steal_string (val);
1476       }
1477       break;
1478 
1479     case GCONF_VALUE_BOOL:
1480       *((gboolean*)retloc) = gconf_value_get_bool(val);
1481       break;
1482 
1483     case GCONF_VALUE_SCHEMA:
1484       *((GConfSchema**)retloc) = gconf_value_steal_schema(val);
1485       break;
1486 
1487     default:
1488       g_assert_not_reached();
1489       break;
1490     }
1491 }
1492 
1493 gboolean
gconf_value_pair_to_primitive_pair_destructive(GConfValue * val,GConfValueType car_type,GConfValueType cdr_type,gpointer car_retloc,gpointer cdr_retloc,GError ** err)1494 gconf_value_pair_to_primitive_pair_destructive(GConfValue* val,
1495                                                GConfValueType car_type,
1496                                                GConfValueType cdr_type,
1497                                                gpointer car_retloc,
1498                                                gpointer cdr_retloc,
1499                                                GError** err)
1500 {
1501   GConfValue* car;
1502   GConfValue* cdr;
1503 
1504   g_return_val_if_fail(val != NULL, FALSE);
1505   g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, FALSE);
1506   g_return_val_if_fail(car_type != GCONF_VALUE_LIST, FALSE);
1507   g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, FALSE);
1508   g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, FALSE);
1509   g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, FALSE);
1510   g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, FALSE);
1511   g_return_val_if_fail(car_retloc != NULL, FALSE);
1512   g_return_val_if_fail(cdr_retloc != NULL, FALSE);
1513   g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
1514 
1515   if (val->type != GCONF_VALUE_PAIR)
1516     {
1517       if (err)
1518         *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1519                                _("Expected pair, got %s"),
1520                                gconf_value_type_to_string(val->type));
1521       gconf_value_free(val);
1522       return FALSE;
1523     }
1524 
1525   car = gconf_value_get_car(val);
1526   cdr = gconf_value_get_cdr(val);
1527 
1528   if (car == NULL ||
1529       cdr == NULL)
1530     {
1531       if (err)
1532         *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1533                                _("Expected (%s,%s) pair, got a pair with one or both values missing"),
1534                                gconf_value_type_to_string(car_type),
1535                                gconf_value_type_to_string(cdr_type));
1536 
1537       gconf_value_free(val);
1538       return FALSE;
1539     }
1540 
1541   g_assert(car != NULL);
1542   g_assert(cdr != NULL);
1543 
1544   if (car->type != car_type ||
1545       cdr->type != cdr_type)
1546     {
1547       if (err)
1548         *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1549                                _("Expected pair of type (%s,%s) got type (%s,%s)"),
1550                                gconf_value_type_to_string(car_type),
1551                                gconf_value_type_to_string(cdr_type),
1552                                gconf_value_type_to_string(car->type),
1553                                gconf_value_type_to_string(cdr->type));
1554       gconf_value_free(val);
1555       return FALSE;
1556     }
1557 
1558   primitive_value(car_retloc, car);
1559   primitive_value(cdr_retloc, cdr);
1560 
1561   gconf_value_free(val);
1562 
1563   return TRUE;
1564 }
1565 
1566 
1567 
1568 /*
1569  * Encode/decode
1570  */
1571 
1572 gchar*
gconf_quote_string(const gchar * src)1573 gconf_quote_string   (const gchar* src)
1574 {
1575   gchar* dest;
1576   const gchar* s;
1577   gchar* d;
1578 
1579   g_return_val_if_fail(src != NULL, NULL);
1580 
1581   /* waste memory! woo-hoo! */
1582   dest = g_malloc0(strlen(src)*2+4);
1583 
1584   d = dest;
1585 
1586   *d = '"';
1587   ++d;
1588 
1589   s = src;
1590   while (*s)
1591     {
1592       switch (*s)
1593         {
1594         case '"':
1595           {
1596             *d = '\\';
1597             ++d;
1598             *d = '"';
1599             ++d;
1600           }
1601           break;
1602 
1603         case '\\':
1604           {
1605             *d = '\\';
1606             ++d;
1607             *d = '\\';
1608             ++d;
1609           }
1610           break;
1611 
1612         default:
1613           {
1614             *d = *s;
1615             ++d;
1616           }
1617           break;
1618         }
1619       ++s;
1620     }
1621 
1622   /* End with quote mark and NULL */
1623   *d = '"';
1624   ++d;
1625   *d = '\0';
1626 
1627   return dest;
1628 }
1629 
1630 gchar*
gconf_unquote_string(const gchar * str,const gchar ** end,GError ** err)1631 gconf_unquote_string (const gchar* str, const gchar** end, GError** err)
1632 {
1633   gchar* unq;
1634   gchar* unq_end = NULL;
1635 
1636   g_return_val_if_fail(end != NULL, NULL);
1637   g_return_val_if_fail(err == NULL || *err == NULL, NULL);
1638   g_return_val_if_fail(str != NULL, NULL);
1639 
1640   unq = g_strdup(str);
1641 
1642   gconf_unquote_string_inplace(unq, &unq_end, err);
1643 
1644   *end = (str + (unq_end - unq));
1645 
1646   return unq;
1647 }
1648 
1649 void
gconf_unquote_string_inplace(gchar * str,gchar ** end,GError ** err)1650 gconf_unquote_string_inplace (gchar* str, gchar** end, GError** err)
1651 {
1652   gchar* dest;
1653   gchar* s;
1654 
1655   g_return_if_fail(end != NULL);
1656   g_return_if_fail(err == NULL || *err == NULL);
1657   g_return_if_fail(str != NULL);
1658 
1659   dest = s = str;
1660 
1661   if (*s != '"')
1662     {
1663       if (err)
1664         *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
1665                                _("Quoted string doesn't begin with a quotation mark"));
1666       *end = str;
1667       return;
1668     }
1669 
1670   /* Skip the initial quote mark */
1671   ++s;
1672 
1673   while (*s)
1674     {
1675       g_assert(s > dest); /* loop invariant */
1676 
1677       switch (*s)
1678         {
1679         case '"':
1680           /* End of the string, return now */
1681           *dest = '\0';
1682           ++s;
1683           *end = s;
1684           return;
1685 
1686         case '\\':
1687           /* Possible escaped quote or \ */
1688           ++s;
1689           if (*s == '"')
1690             {
1691               *dest = *s;
1692               ++s;
1693               ++dest;
1694             }
1695           else if (*s == '\\')
1696             {
1697               *dest = *s;
1698               ++s;
1699               ++dest;
1700             }
1701           else
1702             {
1703               /* not an escaped char */
1704               *dest = '\\';
1705               ++dest;
1706               /* ++s already done. */
1707             }
1708           break;
1709 
1710         default:
1711           *dest = *s;
1712           ++dest;
1713           ++s;
1714           break;
1715         }
1716 
1717       g_assert(s > dest); /* loop invariant */
1718     }
1719 
1720   /* If we reach here this means the close quote was never encountered */
1721 
1722   *dest = '\0';
1723 
1724   if (err)
1725     *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
1726                            _("Quoted string doesn't end with a quotation mark"));
1727   *end = s;
1728   return;
1729 }
1730 
1731 /* The encoding format
1732 
1733    The first byte of the encoded string is the type of the value:
1734 
1735     i  int
1736     b  bool
1737     f  float
1738     s  string
1739     c  schema
1740     p  pair
1741     l  list
1742     v  invalid
1743 
1744     For int, the rest of the encoded value is the integer to be parsed with atoi()
1745     For bool, the rest is 't' or 'f'
1746     For float, the rest is a float to parse with g_strtod()
1747     For string, the rest is the string (not quoted)
1748     For schema, the encoding is complicated; see below.
1749     For pair, the rest is two primitive encodings (ibcfs), quoted, separated by a comma,
1750               car before cdr
1751     For list, first character is type, the rest is primitive encodings, quoted,
1752               separated by commas
1753 
1754     Schema:
1755 
1756     After the 'c' indicating schema, the second character is a byte indicating
1757     the type the schema expects. Then a comma, and the quoted locale, or "" for none.
1758     comma, and quoted short description; comma, quoted long description; comma, default
1759     value in the encoded format given above, quoted.
1760 */
1761 
type_byte(GConfValueType type)1762 static gchar type_byte(GConfValueType type)
1763 {
1764   switch (type)
1765     {
1766     case GCONF_VALUE_INT:
1767       return 'i';
1768 
1769     case GCONF_VALUE_BOOL:
1770       return 'b';
1771 
1772     case GCONF_VALUE_FLOAT:
1773       return 'f';
1774 
1775     case GCONF_VALUE_STRING:
1776       return 's';
1777 
1778     case GCONF_VALUE_SCHEMA:
1779       return 'c';
1780 
1781     case GCONF_VALUE_LIST:
1782       return 'l';
1783 
1784     case GCONF_VALUE_PAIR:
1785       return 'p';
1786 
1787     case GCONF_VALUE_INVALID:
1788       return 'v';
1789 
1790     default:
1791       g_assert_not_reached();
1792       return '\0';
1793     }
1794 }
1795 
1796 static GConfValueType
byte_type(gchar byte)1797 byte_type(gchar byte)
1798 {
1799   switch (byte)
1800     {
1801     case 'i':
1802       return GCONF_VALUE_INT;
1803 
1804     case 'b':
1805       return GCONF_VALUE_BOOL;
1806 
1807     case 's':
1808       return GCONF_VALUE_STRING;
1809 
1810     case 'c':
1811       return GCONF_VALUE_SCHEMA;
1812 
1813     case 'f':
1814       return GCONF_VALUE_FLOAT;
1815 
1816     case 'l':
1817       return GCONF_VALUE_LIST;
1818 
1819     case 'p':
1820       return GCONF_VALUE_PAIR;
1821 
1822     case 'v':
1823       return GCONF_VALUE_INVALID;
1824 
1825     default:
1826       return GCONF_VALUE_INVALID;
1827     }
1828 }
1829 
1830 GConfValue*
gconf_value_decode(const gchar * encoded)1831 gconf_value_decode (const gchar* encoded)
1832 {
1833   GConfValueType type;
1834   GConfValue* val;
1835   const gchar* s;
1836 
1837   type = byte_type(*encoded);
1838 
1839   if (type == GCONF_VALUE_INVALID)
1840     return NULL;
1841 
1842   if (!g_utf8_validate (encoded, -1, NULL))
1843     {
1844       gconf_log (GCL_ERR, _("Encoded value is not valid UTF-8"));
1845       return NULL;
1846     }
1847 
1848   val = gconf_value_new(type);
1849 
1850   s = encoded + 1;
1851 
1852   switch (val->type)
1853     {
1854     case GCONF_VALUE_INT:
1855       gconf_value_set_int(val, atoi(s));
1856       break;
1857 
1858     case GCONF_VALUE_BOOL:
1859       gconf_value_set_bool(val, *s == 't' ? TRUE : FALSE);
1860       break;
1861 
1862     case GCONF_VALUE_FLOAT:
1863       {
1864         double d;
1865         gchar* endptr = NULL;
1866 
1867         d = g_strtod(s, &endptr);
1868         if (endptr == s)
1869           g_warning("Failure converting string to double in %s", G_STRFUNC);
1870         gconf_value_set_float(val, d);
1871       }
1872       break;
1873 
1874     case GCONF_VALUE_STRING:
1875       {
1876         gconf_value_set_string(val, s);
1877       }
1878       break;
1879 
1880     case GCONF_VALUE_SCHEMA:
1881       {
1882         GConfSchema* sc = gconf_schema_new();
1883         const gchar* end = NULL;
1884         gchar* unquoted;
1885 
1886         gconf_value_set_schema_nocopy(val, sc);
1887 
1888         gconf_schema_set_type(sc, byte_type(*s));
1889         ++s;
1890         gconf_schema_set_list_type(sc, byte_type(*s));
1891         ++s;
1892         gconf_schema_set_car_type(sc, byte_type(*s));
1893         ++s;
1894         gconf_schema_set_cdr_type(sc, byte_type(*s));
1895         ++s;
1896 
1897         if (*s != ',')
1898           g_warning("no comma after types in schema");
1899 
1900 	++s;
1901 
1902         /* locale */
1903         unquoted = gconf_unquote_string(s, &end, NULL);
1904 
1905         gconf_schema_set_locale(sc, unquoted);
1906 
1907         g_free(unquoted);
1908 
1909         if (*end != ',')
1910           g_warning("no comma after locale in schema");
1911 
1912         ++end;
1913         s = end;
1914 
1915         /* short */
1916         unquoted = gconf_unquote_string(s, &end, NULL);
1917 
1918         gconf_schema_set_short_desc(sc, unquoted);
1919 
1920         g_free(unquoted);
1921 
1922         if (*end != ',')
1923           g_warning("no comma after short desc in schema");
1924 
1925         ++end;
1926         s = end;
1927 
1928         /* long */
1929         unquoted = gconf_unquote_string(s, &end, NULL);
1930 
1931         gconf_schema_set_long_desc(sc, unquoted);
1932 
1933         g_free(unquoted);
1934 
1935         if (*end != ',')
1936           g_warning("no comma after long desc in schema");
1937 
1938         ++end;
1939         s = end;
1940 
1941         /* default value */
1942         unquoted = gconf_unquote_string(s, &end, NULL);
1943 
1944         gconf_schema_set_default_value_nocopy(sc, gconf_value_decode(unquoted));
1945 
1946         g_free(unquoted);
1947 
1948         if (*end != '\0')
1949           g_warning("trailing junk after encoded schema");
1950       }
1951       break;
1952 
1953     case GCONF_VALUE_LIST:
1954       {
1955         GSList* value_list = NULL;
1956 
1957         gconf_value_set_list_type(val, byte_type(*s));
1958 	++s;
1959 
1960         while (*s)
1961           {
1962             gchar* unquoted;
1963             const gchar* end;
1964 
1965             GConfValue* elem;
1966 
1967             unquoted = gconf_unquote_string(s, &end, NULL);
1968 
1969             elem = gconf_value_decode(unquoted);
1970 
1971             g_free(unquoted);
1972 
1973             if (elem)
1974               value_list = g_slist_prepend(value_list, elem);
1975 
1976             s = end;
1977             if (*s == ',')
1978               ++s;
1979             else if (*s != '\0')
1980               {
1981                 g_warning("weird character in encoded list");
1982                 break; /* error */
1983               }
1984           }
1985 
1986         value_list = g_slist_reverse(value_list);
1987 
1988         gconf_value_set_list_nocopy(val, value_list);
1989       }
1990       break;
1991 
1992     case GCONF_VALUE_PAIR:
1993       {
1994         gchar* unquoted;
1995         const gchar* end;
1996 
1997         GConfValue* car;
1998         GConfValue* cdr;
1999 
2000         unquoted = gconf_unquote_string(s, &end, NULL);
2001 
2002         car = gconf_value_decode(unquoted);
2003 
2004         g_free(unquoted);
2005 
2006         s = end;
2007         if (*s == ',')
2008           ++s;
2009         else
2010           {
2011             g_warning("weird character in encoded pair");
2012           }
2013 
2014         unquoted = gconf_unquote_string(s, &end, NULL);
2015 
2016         cdr = gconf_value_decode(unquoted);
2017         g_free(unquoted);
2018 
2019 
2020         gconf_value_set_car_nocopy(val, car);
2021         gconf_value_set_cdr_nocopy(val, cdr);
2022       }
2023       break;
2024 
2025     default:
2026       g_assert_not_reached();
2027       break;
2028     }
2029 
2030   return val;
2031 }
2032 
2033 gchar*
gconf_value_encode(GConfValue * val)2034 gconf_value_encode (GConfValue* val)
2035 {
2036   gchar* retval = NULL;
2037 
2038   g_return_val_if_fail(val != NULL, NULL);
2039 
2040   switch (val->type)
2041     {
2042     case GCONF_VALUE_INT:
2043       retval = g_strdup_printf("i%d", gconf_value_get_int(val));
2044       break;
2045 
2046     case GCONF_VALUE_BOOL:
2047       retval = g_strdup_printf("b%c", gconf_value_get_bool(val) ? 't' : 'f');
2048       break;
2049 
2050     case GCONF_VALUE_FLOAT:
2051       retval = g_strdup_printf("f%g", gconf_value_get_float(val));
2052       break;
2053 
2054     case GCONF_VALUE_STRING:
2055       retval = g_strdup_printf("s%s", gconf_value_get_string(val));
2056       break;
2057 
2058     case GCONF_VALUE_SCHEMA:
2059       {
2060         gchar* tmp;
2061         gchar* quoted;
2062         gchar* encoded;
2063         GConfSchema* sc;
2064 
2065         sc = gconf_value_get_schema(val);
2066 
2067         tmp = g_strdup_printf("c%c%c%c%c,",
2068 			      type_byte(gconf_schema_get_type(sc)),
2069 			      type_byte(gconf_schema_get_list_type(sc)),
2070 			      type_byte(gconf_schema_get_car_type(sc)),
2071 			      type_byte(gconf_schema_get_cdr_type(sc)));
2072 
2073         quoted = gconf_quote_string(gconf_schema_get_locale(sc) ?
2074                                     gconf_schema_get_locale(sc) : "");
2075         retval = g_strconcat(tmp, quoted, ",", NULL);
2076 
2077         g_free(tmp);
2078         g_free(quoted);
2079 
2080         tmp = retval;
2081         quoted = gconf_quote_string(gconf_schema_get_short_desc(sc) ?
2082                                     gconf_schema_get_short_desc(sc) : "");
2083 
2084         retval = g_strconcat(tmp, quoted, ",", NULL);
2085 
2086         g_free(tmp);
2087         g_free(quoted);
2088 
2089 
2090         tmp = retval;
2091         quoted = gconf_quote_string(gconf_schema_get_long_desc(sc) ?
2092                                     gconf_schema_get_long_desc(sc) : "");
2093 
2094         retval = g_strconcat(tmp, quoted, ",", NULL);
2095 
2096         g_free(tmp);
2097         g_free(quoted);
2098 
2099 
2100         if (gconf_schema_get_default_value(sc) != NULL)
2101           encoded = gconf_value_encode(gconf_schema_get_default_value(sc));
2102         else
2103           encoded = g_strdup("");
2104 
2105         tmp = retval;
2106 
2107         quoted = gconf_quote_string(encoded);
2108 
2109         retval = g_strconcat(tmp, quoted, NULL);
2110 
2111         g_free(tmp);
2112         g_free(quoted);
2113         g_free(encoded);
2114       }
2115       break;
2116 
2117     case GCONF_VALUE_LIST:
2118       {
2119         GSList* tmp;
2120 
2121         retval = g_strdup_printf("l%c", type_byte(gconf_value_get_list_type(val)));
2122 
2123         tmp = gconf_value_get_list(val);
2124 
2125         while (tmp != NULL)
2126           {
2127             GConfValue* elem = tmp->data;
2128             gchar* encoded;
2129             gchar* quoted;
2130 
2131             g_assert(elem != NULL);
2132 
2133             encoded = gconf_value_encode(elem);
2134 
2135             quoted = gconf_quote_string(encoded);
2136 
2137             g_free(encoded);
2138 
2139             {
2140               gchar* free_me;
2141               free_me = retval;
2142 
2143               retval = g_strconcat(retval, ",", quoted, NULL);
2144 
2145               g_free(quoted);
2146               g_free(free_me);
2147             }
2148 
2149             tmp = g_slist_next(tmp);
2150           }
2151       }
2152       break;
2153 
2154     case GCONF_VALUE_PAIR:
2155       {
2156         gchar* car_encoded;
2157         gchar* cdr_encoded;
2158         gchar* car_quoted;
2159         gchar* cdr_quoted;
2160 
2161         car_encoded = gconf_value_encode(gconf_value_get_car(val));
2162         cdr_encoded = gconf_value_encode(gconf_value_get_cdr(val));
2163 
2164         car_quoted = gconf_quote_string(car_encoded);
2165         cdr_quoted = gconf_quote_string(cdr_encoded);
2166 
2167         retval = g_strconcat("p", car_quoted, ",", cdr_quoted, NULL);
2168 
2169         g_free(car_encoded);
2170         g_free(cdr_encoded);
2171         g_free(car_quoted);
2172         g_free(cdr_quoted);
2173       }
2174       break;
2175 
2176     default:
2177       g_assert_not_reached();
2178       break;
2179 
2180     }
2181 
2182   return retval;
2183 }
2184 
2185 #ifdef HAVE_CORBA
2186 
2187 /*
2188  * Locks
2189  */
2190 
2191 /*
2192  * Locks works as follows. We have a lock directory to hold the locking
2193  * mess, and we have an IOR file inside the lock directory with the
2194  * gconfd IOR, and we have an fcntl() lock on the IOR file. The IOR
2195  * file is created atomically using a temporary file, then link()
2196  */
2197 
2198 struct _GConfLock {
2199   gchar *lock_directory;
2200   gchar *iorfile;
2201   int    lock_fd;
2202 };
2203 
2204 static void
gconf_lock_destroy(GConfLock * lock)2205 gconf_lock_destroy (GConfLock* lock)
2206 {
2207   if (lock->lock_fd >= 0)
2208     close (lock->lock_fd);
2209   g_free (lock->iorfile);
2210   g_free (lock->lock_directory);
2211   g_free (lock);
2212 }
2213 
2214 #ifndef G_OS_WIN32
2215 
2216 static void
set_close_on_exec(int fd)2217 set_close_on_exec (int fd)
2218 {
2219 #if defined (F_GETFD) && defined (FD_CLOEXEC)
2220   int val;
2221 
2222   val = fcntl (fd, F_GETFD, 0);
2223   if (val < 0)
2224     {
2225       gconf_log (GCL_DEBUG, "couldn't F_GETFD: %s\n", g_strerror (errno));
2226       return;
2227     }
2228 
2229   val |= FD_CLOEXEC;
2230 
2231   if (fcntl (fd, F_SETFD, val) < 0)
2232     gconf_log (GCL_DEBUG, "couldn't F_SETFD: %s\n", g_strerror (errno));
2233 #endif
2234 }
2235 
2236 #endif
2237 
2238 #ifdef F_SETLK
2239 /* Your basic Stevens cut-and-paste */
2240 static int
lock_reg(int fd,int cmd,int type,off_t offset,int whence,off_t len)2241 lock_reg (int fd, int cmd, int type, off_t offset, int whence, off_t len)
2242 {
2243   struct flock lock;
2244 
2245   lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
2246   lock.l_start = offset; /* byte offset relative to whence */
2247   lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
2248   lock.l_len = len; /* #bytes, 0 for eof */
2249 
2250   return fcntl (fd, cmd, &lock);
2251 }
2252 #endif
2253 
2254 #ifdef F_SETLK
2255 #define lock_entire_file(fd) \
2256   lock_reg ((fd), F_SETLK, F_WRLCK, 0, SEEK_SET, 0)
2257 #define unlock_entire_file(fd) \
2258   lock_reg ((fd), F_SETLK, F_UNLCK, 0, SEEK_SET, 0)
2259 #elif defined (G_OS_WIN32)
2260 /* We don't use these macros */
2261 #else
2262 #warning Please implement proper locking
2263 #define lock_entire_file(fd) 0
2264 #define unlock_entire_file(fd) 0
2265 #endif
2266 
2267 static gboolean
file_locked_by_someone_else(int fd)2268 file_locked_by_someone_else (int fd)
2269 {
2270 #ifdef F_SETLK
2271   struct flock lock;
2272 
2273   lock.l_type = F_WRLCK;
2274   lock.l_start = 0;
2275   lock.l_whence = SEEK_SET;
2276   lock.l_len = 0;
2277 
2278   if (fcntl (fd, F_GETLK, &lock) < 0)
2279     return TRUE; /* pretend it's locked */
2280 
2281   if (lock.l_type == F_UNLCK)
2282     return FALSE; /* we have the lock */
2283   else
2284     return TRUE; /* someone else has it */
2285 #else
2286   return FALSE;
2287 #endif
2288 }
2289 
2290 #ifndef G_OS_WIN32
2291 
2292 static char*
unique_filename(const char * directory)2293 unique_filename (const char *directory)
2294 {
2295   char *guid;
2296   char *uniquefile;
2297 
2298   guid = gconf_unique_key ();
2299   uniquefile = g_strconcat (directory, "/", guid, NULL);
2300   g_free (guid);
2301 
2302   return uniquefile;
2303 }
2304 
2305 #endif
2306 
2307 static int
create_new_locked_file(const gchar * directory,const gchar * filename,GError ** err)2308 create_new_locked_file (const gchar *directory,
2309                         const gchar *filename,
2310                         GError     **err)
2311 {
2312   int fd;
2313   gboolean got_lock = FALSE;
2314 
2315 #ifndef G_OS_WIN32
2316 
2317   char *uniquefile = unique_filename (directory);
2318 
2319   fd = open (uniquefile, O_WRONLY | O_CREAT, 0700);
2320 
2321   /* Lock our temporary file, lock hopefully applies to the
2322    * inode and so also counts once we link it to the new name
2323    */
2324   if (lock_entire_file (fd) < 0)
2325     {
2326       g_set_error (err,
2327                    GCONF_ERROR,
2328                    GCONF_ERROR_LOCK_FAILED,
2329                    _("Could not lock temporary file '%s': %s"),
2330                    uniquefile, g_strerror (errno));
2331       goto out;
2332     }
2333 
2334   /* Create lockfile as a link to unique file */
2335   if (link (uniquefile, filename) == 0)
2336     {
2337       /* filename didn't exist before, and open succeeded, and we have the lock */
2338       got_lock = TRUE;
2339       goto out;
2340     }
2341   else
2342     {
2343       /* see if the link really succeeded */
2344       struct stat sb;
2345       if (stat (uniquefile, &sb) == 0 &&
2346           sb.st_nlink == 2)
2347         {
2348           got_lock = TRUE;
2349           goto out;
2350         }
2351       else
2352         {
2353           g_set_error (err,
2354                        GCONF_ERROR,
2355                        GCONF_ERROR_LOCK_FAILED,
2356                        _("Could not create file '%s', probably because it already exists"),
2357                        filename);
2358           goto out;
2359         }
2360     }
2361 
2362  out:
2363   if (got_lock)
2364     set_close_on_exec (fd);
2365 
2366   unlink (uniquefile);
2367   g_free (uniquefile);
2368 
2369 #else
2370 
2371   if (G_WIN32_HAVE_WIDECHAR_API ())
2372     {
2373       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
2374       fd = _wsopen (wfilename, O_WRONLY|O_CREAT|O_EXCL, SH_DENYWR, 0700);
2375       g_free (wfilename);
2376     }
2377   else
2378     {
2379       char *cpfilename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
2380       fd = _sopen (cpfilename, O_WRONLY|O_CREAT|O_EXCL, SH_DENYWR, 0700);
2381       g_free (cpfilename);
2382     }
2383 
2384   got_lock = (fd >= 0);
2385 
2386 #endif
2387 
2388   if (!got_lock)
2389     {
2390       if (fd >= 0)
2391         close (fd);
2392       fd = -1;
2393     }
2394 
2395   return fd;
2396 }
2397 
2398 static int
open_empty_locked_file(const gchar * directory,const gchar * filename,GError ** err)2399 open_empty_locked_file (const gchar *directory,
2400                         const gchar *filename,
2401                         GError     **err)
2402 {
2403   int fd;
2404 
2405   fd = create_new_locked_file (directory, filename, NULL);
2406 
2407   if (fd >= 0)
2408     return fd;
2409 
2410   /* We failed to create the file, most likely because it already
2411    * existed; try to get the lock on the existing file, and if we can
2412    * get that lock, delete it, then start over.
2413    */
2414 
2415 #ifndef G_OS_WIN32
2416 
2417   fd = open (filename, O_RDWR, 0700);
2418   if (fd < 0)
2419     {
2420       /* File has gone away? */
2421       g_set_error (err,
2422                    GCONF_ERROR,
2423                    GCONF_ERROR_LOCK_FAILED,
2424                    _("Failed to create or open '%s'"),
2425                    filename);
2426       return -1;
2427     }
2428 
2429   if (lock_entire_file (fd) < 0)
2430     {
2431       g_set_error (err,
2432                    GCONF_ERROR,
2433                    GCONF_ERROR_LOCK_FAILED,
2434                    _("Failed to lock '%s': probably another process has the lock, or your operating system has NFS file locking misconfigured (%s)"),
2435                    filename, g_strerror (errno));
2436       close (fd);
2437       return -1;
2438     }
2439 
2440   /* We have the lock on filename, so delete it */
2441   /* FIXME this leaves .nfs32423432 cruft */
2442   unlink (filename);
2443   close (fd);
2444   fd = -1;
2445 
2446 #else
2447   /* Unlinking open files fail on Win32 */
2448 
2449   if (g_remove (filename) == -1)
2450     {
2451       g_set_error (err,
2452 		   GCONF_ERROR,
2453 		   GCONF_ERROR_LOCK_FAILED,
2454 		   _("Failed to remove '%s': %s"),
2455 		   filename, g_strerror (errno));
2456       return -1;
2457     }
2458 #endif
2459 
2460   /* Now retry creating our file */
2461   fd = create_new_locked_file (directory, filename, err);
2462 
2463   return fd;
2464 }
2465 
2466 static char *
get_ior(gboolean start_if_not_found,GString * failure_log)2467 get_ior (gboolean start_if_not_found,
2468          GString  *failure_log)
2469 {
2470         GDBusConnection *connection;
2471         GVariant *value;
2472         char *ior;
2473         GError *error = NULL;
2474 
2475         /* if the bus isn't running and we don't want to start gconfd then
2476          * we don't want to autolaunch the bus either, so bail early.
2477          */
2478         if ((g_getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL && g_getenv ("DBUS_LAUNCHD_SESSION_BUS_SOCKET") == NULL ) &&
2479            (!start_if_not_found || g_getenv ("DISPLAY") == NULL)) {
2480                 if (failure_log)
2481                     g_string_append_printf (failure_log,
2482                                             _("Not running within active session"));
2483                 return NULL;
2484         }
2485 
2486         g_type_init ();
2487 
2488         connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
2489         if (connection == NULL) {
2490                 if (failure_log)
2491                     g_string_append_printf (failure_log,
2492                                             _("Failed to get connection to session: %s"),
2493                                             error->message);
2494                 g_error_free (error);
2495                 return NULL;
2496         }
2497 
2498         value = g_dbus_connection_call_sync (connection,
2499                                              "org.gnome.GConf",
2500                                              "/org/gnome/GConf",
2501                                              "org.gnome.GConf",
2502                                              "GetIOR",
2503                                              g_variant_new ("()"),
2504                                              G_VARIANT_TYPE ("(s)"),
2505                                              start_if_not_found ? G_DBUS_CALL_FLAGS_NONE
2506                                                                 : G_DBUS_CALL_FLAGS_NO_AUTO_START,
2507                                              -1,
2508                                              NULL,
2509                                              &error);
2510         g_object_unref (connection);
2511 
2512         if (value == NULL) {
2513                 if (failure_log)
2514                     g_string_append_printf (failure_log,
2515                                             _("GetIOR failed: %s"),
2516                                             error->message);
2517 
2518                 g_error_free (error);
2519                 return NULL;
2520         }
2521 
2522         g_variant_get (value, "(s)", &ior, NULL);
2523         g_variant_unref (value);
2524 
2525         return ior;
2526 }
2527 
2528 static ConfigServer
gconf_get_server(gboolean start_if_not_found,GString * failure_log)2529 gconf_get_server (gboolean  start_if_not_found,
2530                   GString  *failure_log)
2531 {
2532   ConfigServer server;
2533   char *ior;
2534   CORBA_ORB orb;
2535   CORBA_Environment ev;
2536 
2537   ior = get_ior (start_if_not_found, failure_log);
2538 
2539   if (ior == NULL)
2540     {
2541       return CORBA_OBJECT_NIL;
2542     }
2543 
2544   CORBA_exception_init (&ev);
2545   orb = gconf_orb_get ();
2546 
2547   if (orb == NULL)
2548     {
2549       if (failure_log)
2550         {
2551           g_string_append_printf (failure_log,
2552                                 _("couldn't contact ORB to resolve existing gconfd object reference"));
2553           g_free (ior);
2554         }
2555       return CORBA_OBJECT_NIL;
2556     }
2557 
2558   server = CORBA_ORB_string_to_object (orb, (char*) ior, &ev);
2559   CORBA_exception_free (&ev);
2560 
2561   if (server == CORBA_OBJECT_NIL &&
2562       failure_log)
2563     g_string_append_printf (failure_log,
2564                             _("Failed to convert IOR '%s' to an object reference"),
2565                             ior);
2566 
2567   g_free (ior);
2568 
2569   return server;
2570 }
2571 
2572 static GConfLock *
gconf_get_lock_or_current_holder(const gchar * lock_directory,ConfigServer * current_server,GError ** err)2573 gconf_get_lock_or_current_holder (const gchar  *lock_directory,
2574                                   ConfigServer *current_server,
2575                                   GError      **err)
2576 {
2577   GConfLock* lock;
2578 
2579   g_return_val_if_fail(lock_directory != NULL, NULL);
2580 
2581   if (current_server)
2582     *current_server = CORBA_OBJECT_NIL;
2583 
2584   if (g_mkdir (lock_directory, 0700) < 0 &&
2585       errno != EEXIST)
2586     {
2587       int errsv = errno;
2588 
2589       gconf_set_error (err,
2590                        GCONF_ERROR_LOCK_FAILED,
2591                        _("couldn't create directory `%s': %s"),
2592                        lock_directory, g_strerror (errsv));
2593 
2594       return NULL;
2595     }
2596 
2597   lock = g_new0 (GConfLock, 1);
2598 
2599   lock->lock_directory = g_strdup (lock_directory);
2600 
2601   lock->iorfile = g_strconcat (lock->lock_directory, "/ior", NULL);
2602 
2603   /* Check the current IOR file and ping its daemon */
2604 
2605   lock->lock_fd = open_empty_locked_file (lock->lock_directory,
2606                                           lock->iorfile,
2607                                           err);
2608 
2609   if (lock->lock_fd < 0)
2610     {
2611       /* We didn't get the lock. Read the old server, and provide
2612        * it to the caller. Error is already set.
2613        */
2614       if (current_server)
2615         *current_server = gconf_get_server (FALSE, NULL);
2616 
2617       gconf_lock_destroy (lock);
2618 
2619       return NULL;
2620     }
2621   else
2622     {
2623       /* Write IOR to lockfile */
2624       const gchar* ior;
2625       int retval;
2626       gchar* s;
2627 
2628       s = g_strdup_printf ("%u:", (guint) getpid ());
2629 
2630       retval = write (lock->lock_fd, s, strlen (s));
2631 
2632       g_free (s);
2633 
2634       if (retval >= 0)
2635         {
2636           ior = gconf_get_daemon_ior();
2637 
2638           if (ior == NULL)
2639             retval = write (lock->lock_fd, "none", 4);
2640           else
2641             retval = write (lock->lock_fd, ior, strlen (ior));
2642         }
2643 
2644       if (retval < 0)
2645         {
2646           gconf_set_error (err,
2647                            GCONF_ERROR_LOCK_FAILED,
2648                            _("Can't write to file `%s': %s"),
2649                            lock->iorfile, g_strerror (errno));
2650 
2651           g_unlink (lock->iorfile);
2652           gconf_lock_destroy (lock);
2653 
2654           return NULL;
2655         }
2656     }
2657 
2658   return lock;
2659 }
2660 
2661 GConfLock*
gconf_get_lock(const gchar * lock_directory,GError ** err)2662 gconf_get_lock (const gchar *lock_directory,
2663                 GError     **err)
2664 {
2665   return gconf_get_lock_or_current_holder (lock_directory, NULL, err);
2666 }
2667 
2668 gboolean
gconf_release_lock(GConfLock * lock,GError ** err)2669 gconf_release_lock (GConfLock *lock,
2670                     GError   **err)
2671 {
2672   gboolean retval;
2673   char *uniquefile;
2674 
2675   retval = FALSE;
2676   uniquefile = NULL;
2677 
2678   /* A paranoia check to avoid disaster if e.g.
2679    * some random client code opened and closed the
2680    * lockfile (maybe Nautilus checking its MIME type or
2681    * something)
2682    */
2683   if (lock->lock_fd < 0 ||
2684       file_locked_by_someone_else (lock->lock_fd))
2685     {
2686       g_set_error (err,
2687                    GCONF_ERROR,
2688                    GCONF_ERROR_FAILED,
2689                    _("We didn't have the lock on file `%s', but we should have"),
2690                    lock->iorfile);
2691       goto out;
2692     }
2693 
2694 #ifndef G_OS_WIN32
2695 
2696   /* To avoid annoying .nfs3435314513453145 files on unlink, which keep us
2697    * from removing the lock directory, we don't want to hold the
2698    * lockfile open after removing all links to it. But we can't
2699    * close it then unlink, because then we would be unlinking without
2700    * holding the lock. So, we create a unique filename and link it too
2701    * the locked file, then unlink the locked file, then drop our locks
2702    * and close file descriptors, then unlink the unique filename
2703    */
2704 
2705   uniquefile = unique_filename (lock->lock_directory);
2706 
2707   if (link (lock->iorfile, uniquefile) < 0)
2708     {
2709       g_set_error (err,
2710                    GCONF_ERROR,
2711                    GCONF_ERROR_FAILED,
2712                    _("Failed to link '%s' to '%s': %s"),
2713                    uniquefile, lock->iorfile, g_strerror (errno));
2714 
2715       goto out;
2716     }
2717 
2718   /* Note that we unlink while still holding the lock to avoid races */
2719   if (unlink (lock->iorfile) < 0)
2720     {
2721       g_set_error (err,
2722                    GCONF_ERROR,
2723                    GCONF_ERROR_FAILED,
2724                    _("Failed to remove lock file `%s': %s"),
2725                    lock->iorfile,
2726                    g_strerror (errno));
2727       goto out;
2728     }
2729 
2730 #endif
2731 
2732   /* Now drop our lock */
2733   if (lock->lock_fd >= 0)
2734     {
2735       close (lock->lock_fd);
2736       lock->lock_fd = -1;
2737     }
2738 
2739 #ifndef G_OS_WIN32
2740 
2741   /* Now remove the temporary link we used to avoid .nfs351453 garbage */
2742   if (unlink (uniquefile) < 0)
2743     {
2744       g_set_error (err,
2745                    GCONF_ERROR,
2746                    GCONF_ERROR_FAILED,
2747                    _("Failed to clean up file '%s': %s"),
2748                    uniquefile, g_strerror (errno));
2749 
2750       goto out;
2751     }
2752 
2753 #endif
2754 
2755   /* And finally clean up the directory - this would have failed if
2756    * we had .nfs323423423 junk
2757    */
2758   if (g_rmdir (lock->lock_directory) < 0)
2759     {
2760       g_set_error (err,
2761                    GCONF_ERROR,
2762                    GCONF_ERROR_FAILED,
2763                    _("Failed to remove lock directory `%s': %s"),
2764                    lock->lock_directory,
2765                    g_strerror (errno));
2766       goto out;
2767     }
2768 
2769   retval = TRUE;
2770 
2771  out:
2772 
2773   g_free (uniquefile);
2774   gconf_lock_destroy (lock);
2775   return retval;
2776 }
2777 
2778 static CORBA_ORB gconf_orb = CORBA_OBJECT_NIL;
2779 
2780 CORBA_ORB
gconf_orb_get(void)2781 gconf_orb_get (void)
2782 {
2783   if (gconf_orb == CORBA_OBJECT_NIL)
2784     {
2785       CORBA_Environment ev;
2786       int argc = 1;
2787       char *argv[] = { "gconf", NULL };
2788 
2789       _gconf_init_i18n ();
2790 
2791       CORBA_exception_init (&ev);
2792 
2793       gconf_orb = CORBA_ORB_init (&argc, argv, "orbit-local-orb", &ev);
2794       g_assert (ev._major == CORBA_NO_EXCEPTION);
2795 
2796       CORBA_exception_free (&ev);
2797     }
2798 
2799   return gconf_orb;
2800 }
2801 
2802 int
gconf_orb_release(void)2803 gconf_orb_release (void)
2804 {
2805   int ret = 0;
2806 
2807   if (gconf_orb != CORBA_OBJECT_NIL)
2808     {
2809       CORBA_ORB orb = gconf_orb;
2810       CORBA_Environment ev;
2811 
2812       gconf_orb = CORBA_OBJECT_NIL;
2813 
2814       CORBA_exception_init (&ev);
2815 
2816       CORBA_ORB_destroy (orb, &ev);
2817       CORBA_Object_release ((CORBA_Object)orb, &ev);
2818 
2819       if (ev._major != CORBA_NO_EXCEPTION)
2820         {
2821           ret = 1;
2822         }
2823       CORBA_exception_free (&ev);
2824     }
2825 
2826   return ret;
2827 }
2828 
2829 char*
gconf_get_daemon_dir(void)2830 gconf_get_daemon_dir (void)
2831 {
2832   if (gconf_use_local_locks ())
2833     {
2834       char *s;
2835       char *subdir;
2836       const char *tmpdir;
2837 
2838       subdir = g_strconcat ("gconfd-", g_get_user_name (), NULL);
2839 
2840       if (g_getenv ("GCONF_TMPDIR"))
2841         tmpdir = g_getenv ("GCONF_TMPDIR");
2842       else if (g_getenv ("XDG_RUNTIME_DIR"))
2843         {
2844           g_free (subdir);
2845           subdir = g_strdup ("gconfd");
2846           tmpdir = g_getenv ("XDG_RUNTIME_DIR");
2847         }
2848       else
2849         tmpdir = g_get_tmp_dir ();
2850 
2851       s = g_build_filename (tmpdir, subdir, NULL);
2852 
2853       g_free (subdir);
2854 
2855       return s;
2856     }
2857   else
2858     {
2859 #ifndef G_OS_WIN32
2860       const char *home = g_get_home_dir ();
2861 #else
2862       const char *home = _gconf_win32_get_home_dir ();
2863 #endif
2864       return g_strconcat (home, "/.gconfd", NULL);
2865     }
2866 }
2867 
2868 ConfigServer
gconf_activate_server(gboolean start_if_not_found,GError ** error)2869 gconf_activate_server (gboolean  start_if_not_found,
2870                        GError  **error)
2871 {
2872   ConfigServer server = CORBA_OBJECT_NIL;
2873   GString *failure_log;
2874   CORBA_Environment ev;
2875 
2876   failure_log = g_string_new (NULL);
2877 
2878   g_string_append (failure_log, " 1: ");
2879   server = gconf_get_server (start_if_not_found, failure_log);
2880 
2881   /* Confirm server exists */
2882   CORBA_exception_init (&ev);
2883 
2884   if (!CORBA_Object_is_nil (server, &ev))
2885     {
2886       ConfigServer_ping (server, &ev);
2887 
2888       if (ev._major != CORBA_NO_EXCEPTION)
2889         {
2890           server = CORBA_OBJECT_NIL;
2891 
2892           g_string_append_printf (failure_log,
2893                                   _("Server ping error: %s"),
2894                                   CORBA_exception_id (&ev));
2895         }
2896     }
2897 
2898   CORBA_exception_free (&ev);
2899 
2900   if (server != CORBA_OBJECT_NIL)
2901     {
2902       g_string_free (failure_log, TRUE);
2903       return server;
2904     }
2905 
2906   if (server == CORBA_OBJECT_NIL &&
2907       error &&
2908       *error == NULL)
2909     g_set_error (error,
2910                  GCONF_ERROR,
2911                  GCONF_ERROR_NO_SERVER,
2912                  _("Failed to contact configuration server; the most common cause is a missing or misconfigured D-Bus session bus daemon. See http://projects.gnome.org/gconf/ for information. (Details - %s)"),
2913                  failure_log->len > 0 ? failure_log->str : _("none"));
2914 
2915   g_string_free (failure_log, TRUE);
2916 
2917   return server;
2918 }
2919 
2920 gboolean
gconf_CORBA_Object_equal(gconstpointer a,gconstpointer b)2921 gconf_CORBA_Object_equal (gconstpointer a, gconstpointer b)
2922 {
2923   CORBA_Environment ev;
2924   CORBA_Object _obj_a = (gpointer)a;
2925   CORBA_Object _obj_b = (gpointer)b;
2926   gboolean retval;
2927 
2928   CORBA_exception_init (&ev);
2929   retval = CORBA_Object_is_equivalent(_obj_a, _obj_b, &ev);
2930   CORBA_exception_free (&ev);
2931 
2932   return retval;
2933 }
2934 
2935 guint
gconf_CORBA_Object_hash(gconstpointer key)2936 gconf_CORBA_Object_hash (gconstpointer key)
2937 {
2938   CORBA_Environment ev;
2939   CORBA_Object _obj = (gpointer)key;
2940   CORBA_unsigned_long retval;
2941 
2942   CORBA_exception_init (&ev);
2943   retval = CORBA_Object_hash(_obj, G_MAXUINT, &ev);
2944   CORBA_exception_free (&ev);
2945 
2946   return retval;
2947 }
2948 
2949 #endif /* HAVE_CORBA */
2950 
2951 void
_gconf_init_i18n(void)2952 _gconf_init_i18n (void)
2953 {
2954   static gboolean done = FALSE;
2955 
2956   if (!done)
2957     {
2958       bindtextdomain (GETTEXT_PACKAGE, GCONF_LOCALE_DIR);
2959 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
2960       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2961 #endif
2962       done = TRUE;
2963     }
2964 }
2965 
2966 enum { UNKNOWN, LOCAL, NORMAL };
2967 
2968 gboolean
gconf_use_local_locks(void)2969 gconf_use_local_locks (void)
2970 {
2971   static int local_locks = UNKNOWN;
2972 
2973   if (local_locks == UNKNOWN)
2974     {
2975       const char *l =
2976         g_getenv ("GCONF_GLOBAL_LOCKS");
2977 
2978       if (l && atoi (l) == 1)
2979         local_locks = NORMAL;
2980       else
2981         local_locks = LOCAL;
2982     }
2983 
2984   return local_locks == LOCAL;
2985 }
2986