gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / gregistrysettingsbackend.c
1 /*
2  * Copyright © 2009-10 Sam Thursfield
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Author: Sam Thursfield <ssssam@gmail.com>
20  */
21
22 /* GRegistrySettingsBackend implementation notes:
23  *
24  *   - All settings are stored under the registry path given at construction
25  *     time. Permissions and system-wide defaults are not implemented and will
26  *     probably always be out of scope of the Windows port of GLib.
27  *
28  *   - The registry type system is limited. Most GVariant types are stored as
29  *     literals via g_variant_print/parse(). Strings are stored without the
30  *     quotes that GVariant requires. Integer types are stored as native
31  *     REG_DWORD or REG_QWORD. The REG_MULTI_SZ (string array) type could be
32  *     used to avoid flattening container types.
33  *
34  *   - Notifications are handled; the change event is watched for in a separate
35  *     thread (Windows does not provide a callback API) which sends them with
36  *     g_idle_add to the GLib main loop. The threading is done using Windows
37  *     API functions, so there is no dependence on GThread.
38  *
39  *   - Windows doesn't tell us which value has changed. This means we have to
40  *     maintain a cache of every stored value so we can play spot the
41  *     difference. This should not be a performance issue because if you are
42  *     storing thousands of values in GSettings, you are probably using it
43  *     wrong.
44  *
45  *   - The cache stores the value as a registry type. Because many variants are
46  *     stored as string representations, values which have changed equality but
47  *     not equivalence may trigger spurious change notifications. GSettings
48  *     users must already deal with this possibility and converting all data to
49  *     GVariant values would be more effort.
50  *
51  *   - Because we have to cache every registry value locally, reads are done
52  *     from the cache rather than directly from the registry. Writes update
53  *     both. This means that the backend will not work if the watch thread is
54  *     not running. A GSettings object always subscribes to changes so we can
55  *     be sure that the watch thread will be running, but if for some reason
56  *     the backend is being used directly you should bear that in mind.
57  *
58  *   - The registry is totally user-editable, so we are very forgiving about
59  *     errors in the data we get.
60  *
61  *   - The registry uses backslashes as path separators. GSettings keys only
62  *     allow [A-Za-z\-] so no escaping is needed. No attempt is made to solve
63  *     clashes between keys differing only in case.
64  *
65  *   - RegCreateKeyW is used - We should always make the UTF-8 -> UTF-16
66  *     conversion ourselves to avoid problems when the system language changes.
67  *
68  *   - The Windows registry has the following limitations: a key may not exceed
69  *     255 characters, an entry's value may not exceed 16,383 characters, and
70  *     all the values of a key may not exceed 65,535 characters.
71  *
72  *   - Terminology:
73  *     * in GSettings, a 'key' is eg. /desktop/gnome/background/primary-color
74  *     * in the registry, the 'key' is path, which contains some 'values'.
75  *     * in this file, any GSettings key is a 'key', while a registry key is
76  *       termed a 'path', which contains 'values'.
77  *
78  *   - My set of tests for this backend are currently at:
79  *       http://gitorious.org/gsettings-gtk/gsettings-test.git
80  *
81  *   - There is an undocumented function in ntdll.dll which might be more
82  *     than RegNotifyChangeKeyValue(), NtNotifyChangeKey:
83  *       http://source.winehq.org/source/dlls/ntdll/reg.c#L618
84  *       http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Key/NtNotifyChangeKey.html
85  *
86  *   - If updating the cache ever becomes a performance issue it may make sense
87  *     to use a red-black tree, but I don't currently think it's worth the time
88  */
89
90 #include "config.h"
91
92 #include "gregistrysettingsbackend.h"
93 #include "gsettingsbackend.h"
94 #include "gsettingsbackendinternal.h"
95 #include "giomodule-priv.h"
96
97 #include <glibintl.h>
98
99 #include <windows.h>
100
101 //#define TRACE
102
103 /* GSettings' limit */
104 #define MAX_KEY_NAME_LENGTH   128
105
106 /* Testing (on Windows XP SP3) shows that WaitForMultipleObjects fails with
107  * "The parameter is incorrect" after 64 watches. We need one for the
108  * message_sent cond, which is allowed for in the way the watches_remaining
109  * variable is used.
110  */
111 #define MAX_WATCHES   64
112
113 /* A watch on one registry path and its subkeys */
114 typedef struct
115 {
116   HANDLE event;
117   HKEY hpath;
118   char *prefix;
119   GNode *cache_node;
120 } RegistryWatch;
121
122 /* Simple message passing for the watch thread. Not enough traffic to
123  * justify a queue.
124  */
125 typedef enum
126 {
127   WATCH_THREAD_NONE,
128   WATCH_THREAD_ADD_WATCH,
129   WATCH_THREAD_REMOVE_WATCH,
130   WATCH_THREAD_STOP
131 } WatchThreadMessageType;
132
133 typedef struct
134 {
135   WatchThreadMessageType type;
136   RegistryWatch watch;
137 } WatchThreadMessage;
138
139 typedef struct
140 {
141   GSettingsBackend *owner;
142   HANDLE *thread;
143
144   /* Details of the things we are watching. */
145   int watches_remaining;
146   GPtrArray *events, *handles, *prefixes, *cache_nodes;
147
148   /* Communication with the main thread. Only one message is stored at a time,
149    * to make sure that messages are acknowledged before being overwritten we
150    * create two events - one is signalled when a new message is set, the
151    * other is signalled by the thread when it has processed the message.
152    */
153   WatchThreadMessage message;
154   CRITICAL_SECTION *message_lock;
155   HANDLE message_sent_event, message_received_event;
156 } WatchThreadState;
157
158 #define G_TYPE_REGISTRY_SETTINGS_BACKEND      (g_registry_settings_backend_get_type ())
159 #define G_REGISTRY_SETTINGS_BACKEND(inst)     (G_TYPE_CHECK_INSTANCE_CAST ((inst),         \
160                                                G_TYPE_REGISTRY_SETTINGS_BACKEND, GRegistrySettingsBackend))
161 #define G_IS_REGISTRY_SETTINGS_BACKEND(inst)  (G_TYPE_CHECK_INSTANCE_TYPE ((inst),         \
162                                                G_TYPE_REGISTRY_SETTINGS_BACKEND))
163
164 typedef enum {
165   PROP_REGISTRY_KEY = 1,
166 } GRegistrySettingsBackendProperty;
167
168 typedef GSettingsBackendClass GRegistrySettingsBackendClass;
169
170 typedef struct {
171   GSettingsBackend parent_instance;
172
173   HKEY base_key;
174   gchar *base_path;
175   gunichar2 *base_pathw;
176
177   /* A stored copy of the whole tree being watched. When we receive a change notification
178    * we have to check against this to see what has changed ... every time ...*/
179   CRITICAL_SECTION *cache_lock;
180   GNode *cache_root;
181
182   WatchThreadState *watch;
183 } GRegistrySettingsBackend;
184
185 G_DEFINE_TYPE_WITH_CODE (GRegistrySettingsBackend,
186                          g_registry_settings_backend,
187                          G_TYPE_SETTINGS_BACKEND,
188                          _g_io_modules_ensure_extension_points_registered ();
189                          g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
190                                                          g_define_type_id, "registry", 90))
191
192 /**********************************************************************************
193  * Utility functions
194  **********************************************************************************/
195
196 #include <stdio.h>
197 static void
198 trace (const char *format,
199        ...)
200 {
201 #ifdef TRACE
202   va_list va; va_start (va, format);
203   vprintf (format, va);
204   fflush (stdout);
205   va_end (va);
206 #endif
207 }
208
209 /* g_message including a windows error message. It is not useful to have an
210  * equivalent function for g_warning because none of the registry errors can
211  * result from programmer error (Microsoft programmers don't count), instead
212  * they will mostly occur from people messing with the registry by hand. */
213 static void G_GNUC_PRINTF (2, 3)
214 g_message_win32_error (DWORD        result_code,
215                        const gchar *format,
216                       ...)
217 {
218   va_list va;
219   gchar *message;
220   gchar *win32_error;
221   gchar *win32_message;
222
223   g_return_if_fail (result_code != 0);
224
225   va_start (va, format);
226   message = g_strdup_vprintf (format, va);
227   win32_error = g_win32_error_message (result_code);
228   win32_message = g_strdup_printf ("%s: %s", message, win32_error);
229   g_free (message);
230   g_free (win32_error);
231
232   if (result_code == ERROR_KEY_DELETED)
233     trace ("(%s)", win32_message);
234   else
235     g_message ("%s", win32_message);
236
237   g_free (win32_message);
238 }
239
240 /* Make gsettings key into a registry path & value pair.
241  *
242  * Note that the return value *only* needs freeing - registry_value_name
243  * is a pointer to further inside the same block of memory.
244  */
245 static gchar *
246 parse_key (const gchar  *key_name,
247            const gchar  *registry_prefix,
248            gchar       **value_name)
249 {
250   gchar *path_name, *c;
251
252   /* All key paths are treated as absolute; gsettings doesn't seem to enforce a
253    * preceding /.
254    */
255   if (key_name[0] == '/')
256     key_name++;
257
258   if (registry_prefix == NULL)
259     path_name = g_strdup (key_name);
260   else
261     path_name = g_strjoin ("/", registry_prefix, key_name, NULL);
262
263   /* Prefix is expected to be in registry format (\ separators) so don't escape that. */
264   for (c = path_name + (registry_prefix ? strlen (registry_prefix) : 0); *c != 0; c++)
265     {
266       if (*c == '/')
267         {
268           *c = '\\';
269           *value_name = c;
270         }
271     }
272
273   **value_name = 0;
274   (*value_name)++;
275
276   return path_name;
277 }
278
279 static DWORD
280 g_variant_get_as_dword (GVariant *variant)
281 {
282   switch (g_variant_get_type_string (variant)[0])
283     {
284     case 'b':
285       return g_variant_get_boolean (variant);
286     case 'y':
287       return g_variant_get_byte (variant);
288     case 'n':
289       return g_variant_get_int16 (variant);
290     case 'q':
291       return g_variant_get_uint16 (variant);
292     case 'i':
293       return g_variant_get_int32 (variant);
294     case 'u':
295       return g_variant_get_uint32 (variant);
296     default:
297       g_warn_if_reached ();
298     }
299   return 0;
300 }
301
302 static DWORDLONG
303 g_variant_get_as_qword (GVariant *variant)
304 {
305   switch (g_variant_get_type_string (variant)[0])
306     {
307     case 'x':
308       return g_variant_get_int64 (variant);
309     case 't':
310       return g_variant_get_uint64 (variant);
311     default:
312       g_warn_if_reached ();
313     }
314   return 0;
315 }
316
317 static void
318 handle_read_error (LONG         result,
319                    const gchar *path_name,
320                    const gchar *value_name)
321 {
322   /* file not found means key value not set, this isn't an error for us. */
323   if (result != ERROR_FILE_NOT_FOUND)
324     g_message_win32_error (result, "Unable to query value %s/%s",
325                            path_name, value_name);
326 }
327
328 typedef struct {
329   HKEY handle;
330   const char *name;
331 } HandleNamePair;
332
333 static const HandleNamePair predefined_key_names[] = {
334   { HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT" },
335   { HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" },
336   { HKEY_CURRENT_USER, "HKEY_CURRENT_USER" },
337   { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" },
338   { HKEY_USERS, "HKEY_USERS" }
339 };
340
341 static const gchar*
342 predefined_key_to_string (HKEY key)
343 {
344   for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
345     {
346       if (predefined_key_names[i].handle == key)
347         return predefined_key_names[i].name;
348     }
349
350   g_warning ("gregistrysettingsbackend: unexpected root key (%p)", key);
351   return "";
352 }
353
354 static const gchar*
355 split_registry_path (const gchar *full_path,
356                      HKEY        *root_key)
357 {
358   g_assert (full_path != NULL);
359
360   for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
361     {
362       const gchar *root_name = predefined_key_names[i].name;
363
364       if (g_str_has_prefix (full_path, root_name))
365         {
366           const gchar *rest = full_path + strlen (root_name);
367
368           if (*rest == '\\')
369             {
370               if (root_key != NULL)
371                 *root_key = predefined_key_names[i].handle;
372
373               return ++rest;
374             }
375         }
376     }
377
378   return NULL;
379 }
380
381 /***************************************************************************
382  * Cache of registry values
383  ***************************************************************************/
384
385 /* Generic container for registry values */
386 typedef struct {
387   DWORD type;
388
389   union {
390     gint  dword;  /* FIXME: could inline QWORD on 64-bit systems too */
391     void *ptr;
392   };
393 } RegistryValue;
394
395 static char *
396 registry_value_dump (RegistryValue value)
397 {
398   if (value.type == REG_DWORD)
399     return g_strdup_printf ("%d", value.dword);
400   else if (value.type == REG_QWORD)
401     return g_strdup_printf ("%"G_GINT64_FORMAT, value.ptr == NULL ? 0: *(DWORDLONG *)value.ptr);
402   else if (value.type == REG_SZ)
403     return g_strdup_printf ("%s", (char *)value.ptr);
404   else if (value.type == REG_NONE)
405     return g_strdup_printf ("<empty>");
406   else
407     return g_strdup_printf ("<invalid>");
408 }
409
410 static void
411 registry_value_free (RegistryValue value)
412 {
413   if (value.type == REG_SZ || value.type == REG_QWORD)
414     g_free (value.ptr);
415
416   value.type = REG_NONE;
417   value.ptr = NULL;
418 }
419
420 /* The registry cache is stored as a tree, for easy traversal. Right now we
421  * don't sort it in a clever way. Each node corresponds to a path element
422  * ('key' in registry terms) or a value.
423  *
424  * Each subscription uses the same cache. Because GSettings can subscribe to
425  * the tree at any node any number of times, we need to reference count the
426  * nodes.
427  */
428 typedef struct
429 {
430   /* Component of path that this node represents */
431   gchar *name;
432
433   /* If a watch is subscribed at this point (subscription_count > 0) we can
434    * block its next notification. This is useful because if two watches cover
435    * the same path, both will trigger when it changes. It also allows changes
436    * done by the application to be ignored by the watch thread.
437    */
438   gint32 block_count : 8;
439
440   /* Number of times g_settings_subscribe has been called for this location
441    * (I guess you can't subscribe more than 16383 times) */
442   gint32 subscription_count : 14;
443
444   gint32 ref_count : 9;
445
446   gint32 readable : 1;
447   RegistryValue value;
448 } RegistryCacheItem;
449
450 static GNode *
451 registry_cache_add_item (GNode         *parent,
452                          gchar         *name,
453                          RegistryValue  value,
454                          gint           ref_count)
455 {
456   RegistryCacheItem *item;
457   GNode *cache_node;
458
459   g_return_val_if_fail (name != NULL, NULL);
460   g_return_val_if_fail (parent != NULL, NULL);
461
462   item = g_slice_new (RegistryCacheItem);
463
464   /* Ref count should be the number of watch points above this node */
465   item->ref_count = ref_count;
466
467   item->name = g_strdup (name);
468   item->value = value;
469   item->subscription_count = 0;
470   item->block_count = 0;
471   item->readable = FALSE;
472
473   trace ("\tregistry cache: adding %s to %s\n",
474          name, ((RegistryCacheItem *)parent->data)->name);
475
476   cache_node = g_node_new (item);
477   g_node_append (parent, cache_node);
478
479   return cache_node;
480 }
481
482 /* The reference counting of cache tree nodes works like this: when a node is
483  * subscribed to (GSettings wants us to watch that path and everything below
484  * it) the reference count of that node and everything below is increased, as
485  * well as each parent up to the root.
486  */
487
488 static void
489 _ref_down (GNode *node)
490 {
491   RegistryCacheItem *item = node->data;
492
493   g_node_children_foreach (node, G_TRAVERSE_ALL,
494                            (GNodeForeachFunc)_ref_down, NULL);
495   item->ref_count++;
496 }
497
498 static void
499 registry_cache_ref_tree (GNode *tree)
500 {
501   RegistryCacheItem *item = tree->data;
502   GNode *node = tree->parent;
503
504   g_return_if_fail (tree != NULL);
505
506   item->ref_count++;
507
508   g_node_children_foreach (tree, G_TRAVERSE_ALL,
509                            (GNodeForeachFunc)_ref_down, NULL);
510
511   for (node = tree->parent; node; node = node->parent)
512     {
513       item = node->data;
514       item->ref_count++;
515     }
516 }
517
518 static void
519 registry_cache_item_free (RegistryCacheItem *item)
520 {
521   trace ("\t -- Free node %s\n", item->name);
522
523   g_free (item->name);
524   registry_value_free (item->value);
525   g_slice_free (RegistryCacheItem, item);
526 }
527
528 /* Unreferencing has to be done bottom-up */
529 static void
530 _unref_node (GNode *node)
531 {
532   RegistryCacheItem *item = node->data;
533
534   item->ref_count--;
535
536   g_warn_if_fail (item->ref_count >= 0);
537
538   if (item->ref_count == 0)
539     {
540       registry_cache_item_free (item);
541       g_node_destroy (node);
542     }
543 }
544
545 static void
546 _unref_down (GNode *node)
547 {
548   g_node_children_foreach (node, G_TRAVERSE_ALL,
549                            (GNodeForeachFunc)_unref_down, NULL);
550   _unref_node (node);
551 }
552
553 static void
554 registry_cache_unref_tree (GNode *tree)
555 {
556   GNode *parent = tree->parent, *next_parent;
557
558   _unref_down (tree);
559
560   while (parent)
561     {
562       next_parent = parent->parent;
563       _unref_node (parent);
564       parent = next_parent;
565     }
566 }
567
568 #if 0
569 static void
570 registry_cache_dump (GNode    *cache_node,
571                      gpointer  data)
572 {
573   RegistryCacheItem *item = cache_node->data;
574
575   int depth     = GPOINTER_TO_INT(data),
576       new_depth = depth+1,
577       i;
578
579   g_return_if_fail (cache_node != NULL);
580
581   for (i=0; i<depth; i++)
582     g_print ("  ");
583   if (item == NULL)
584     g_print ("*root*\n");
585   else
586     g_print ("'%s'  [%i] @ %x = %s\n", item->name, item->ref_count, (guint)cache_node,
587              registry_value_dump (item->value));
588   g_node_children_foreach (cache_node, G_TRAVERSE_ALL, registry_cache_dump,
589                            GINT_TO_POINTER (new_depth));
590 }
591 #endif
592
593 typedef struct
594 {
595   gchar *name;
596   GNode *result;
597 } RegistryCacheSearch;
598
599 static gboolean
600 registry_cache_find_compare (GNode    *node,
601                              gpointer  data)
602 {
603   RegistryCacheSearch *search = data;
604   RegistryCacheItem *item = node->data;
605
606   if (item == NULL)  /* root node */
607     return FALSE;
608
609   g_return_val_if_fail (search->name != NULL, FALSE);
610   g_return_val_if_fail (item->name != NULL, FALSE);
611
612   if (strcmp (search->name, item->name) == 0)
613     {
614       search->result = node;
615       return TRUE;
616     }
617
618   return FALSE;
619 }
620
621 static GNode *
622 registry_cache_find_immediate_child (GNode *node,
623                                      gchar *name)
624 {
625   RegistryCacheSearch search;
626
627   search.result = NULL;
628   search.name = name;
629
630   g_node_traverse (node, G_POST_ORDER, G_TRAVERSE_ALL, 2,
631                    registry_cache_find_compare, &search);
632
633   return search.result;
634 }
635
636 static GNode *
637 registry_cache_get_node_for_key_recursive (GNode    *node,
638                                            gchar    *key_name,
639                                            gboolean  create_if_not_found,
640                                            gint      n_parent_watches)
641 {
642   RegistryCacheItem *item;
643   gchar *component = key_name;
644   gchar *c = strchr (component, '/');
645   GNode *child;
646
647   if (c != NULL)
648     *c = 0;
649
650   /* We count up how many watch points we travel through finding this node,
651    * because a new node should have as many references as there are watches at
652    * points above it in the tree.
653    */
654   item = node->data;
655   if (item->subscription_count > 0)
656     n_parent_watches++;
657
658   child = registry_cache_find_immediate_child (node, component);
659   if (child == NULL && create_if_not_found)
660     {
661       RegistryValue null_value = { REG_NONE, {0} };
662
663       child = registry_cache_add_item (node, component,
664                                        null_value, n_parent_watches);
665
666       trace ("\tget node for key recursive: new %x = %s.\n", node, component);
667     }
668
669   /* We are done if there are no more path components. Allow for a trailing /. */
670   if (child == NULL || c == NULL || *(c + 1) == 0)
671     return child;
672
673   trace ("get node for key recursive: next: %s.\n", c + 1);
674
675   return registry_cache_get_node_for_key_recursive (child, c + 1,
676                                                     create_if_not_found,
677                                                     n_parent_watches);
678 }
679
680 /* Look up a GSettings key in the cache. */
681 static GNode *
682 registry_cache_get_node_for_key (GNode       *root,
683                                  const gchar *key_name,
684                                  gboolean     create_if_not_found)
685 {
686   GNode *child = NULL;
687   GNode *result = NULL;
688   gchar *component, *c;
689
690   g_return_val_if_fail (key_name != NULL, NULL);
691
692   if (key_name[0] == '/')
693     key_name++;
694
695   /* Ignore preceding / */
696   component = g_strdup (key_name);
697   c = strchr (component, '/');
698
699   if (c == NULL)
700     {
701       g_free (component);
702       return root;
703     }
704
705   if (c != NULL)
706     *c = 0;
707
708   child = registry_cache_find_immediate_child (root, component);
709   if (child == NULL && create_if_not_found)
710     {
711       RegistryValue null_value = { REG_NONE, {0} };
712
713       /* Reference count is set to 0, tree should be referenced by the caller */
714       child = registry_cache_add_item (root, component,
715                                        null_value, 0);
716
717       trace ("get_node_for_key: New node for component '%s'\n", component);
718     }
719
720   if (*(c + 1) == 0)
721     result = child;
722   else if (child != NULL)
723     result = registry_cache_get_node_for_key_recursive (child, c + 1,
724                                                         create_if_not_found, 0);
725
726   g_free (component);
727
728   return result;
729 }
730
731 /* Check the cache node against the registry key it represents. Return TRUE if
732  * they differ, and update the cache with the new value.
733  */
734 static gboolean
735 registry_cache_update_node (GNode        *cache_node,
736                             RegistryValue registry_value)
737 {
738   RegistryCacheItem *cache_item;
739
740   g_return_val_if_fail (cache_node != NULL, FALSE);
741   g_return_val_if_fail (cache_node->data != NULL, FALSE);
742
743   cache_item = cache_node->data;
744
745   if (registry_value.type != cache_item->value.type)
746     {
747       /* The type has changed. Update cache item and register it as changed.
748        * Either the schema has changed and this is entirely legitimate, or
749        * whenever the app reads the key it will get the default value due to
750        * the type mismatch.
751        */
752       cache_item->value = registry_value;
753       return TRUE;
754     }
755
756   switch (registry_value.type)
757     {
758     case REG_DWORD:
759       {
760         if (cache_item->value.dword == registry_value.dword)
761           return FALSE;
762         else
763           {
764             cache_item->value.dword = registry_value.dword;
765             return TRUE;
766           }
767       }
768     case REG_QWORD:
769       {
770         g_return_val_if_fail (registry_value.ptr != NULL &&
771                               cache_item->value.ptr != NULL, FALSE);
772
773         if (memcmp (registry_value.ptr, cache_item->value.ptr, 8)==0)
774           {
775             g_free (registry_value.ptr);
776             return FALSE;
777           }
778         else
779           {
780             g_free (cache_item->value.ptr);
781             cache_item->value.ptr = registry_value.ptr;
782             return TRUE;
783           }
784       }
785     case REG_SZ:
786       {
787         /* Value should not exist if it is NULL, an empty string is "" */
788         g_return_val_if_fail (cache_item->value.ptr != NULL, FALSE);
789         g_return_val_if_fail (registry_value.ptr != NULL, FALSE);
790
791         if (strcmp (registry_value.ptr, cache_item->value.ptr) == 0)
792           {
793             g_free (registry_value.ptr);
794             return FALSE;
795           }
796         else
797           {
798             g_free (cache_item->value.ptr);
799             cache_item->value.ptr = registry_value.ptr;
800             return TRUE;
801           }
802       }
803     default:
804       g_warning ("gregistrysettingsbackend: registry_cache_update_node: Unhandled value type");
805       return FALSE;
806     }
807 }
808
809 /* Blocking notifications is a useful optimisation. When a change is made
810  * through GSettings we update the cache manually, but a notification is
811  * triggered as well. This function is also used for nested notifications,
812  * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
813  * we will get notified both for /test/foo and /test and it is helpful to block
814  * the second.
815  */
816 static void
817 registry_cache_block_notification (GNode *node)
818 {
819   RegistryCacheItem *item = node->data;
820
821   g_return_if_fail (node != NULL);
822
823   if (item->subscription_count > 0)
824     item->block_count++;
825
826   if (node->parent != NULL)
827     registry_cache_block_notification (node->parent);
828 }
829
830 static void registry_cache_destroy_tree (GNode            *node,
831                                          WatchThreadState *self);
832
833 /***************************************************************************
834  * Reading and writing
835  ***************************************************************************/
836
837 static gboolean
838 registry_read (HKEY           hpath,
839                const gchar   *path_name,
840                const gchar   *value_name,
841                RegistryValue *p_value)
842 {
843   LONG result;
844   DWORD value_data_size;
845   gpointer *buffer;
846   gunichar2 *value_namew;
847
848   g_return_val_if_fail (p_value != NULL, FALSE);
849
850   p_value->type = REG_NONE;
851   p_value->ptr = NULL;
852
853   value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
854
855   result = RegQueryValueExW (hpath, value_namew, 0, &p_value->type, NULL, &value_data_size);
856   if (result != ERROR_SUCCESS)
857     {
858       handle_read_error (result, path_name, value_name);
859       g_free (value_namew);
860       return FALSE;
861     }
862
863   if (p_value->type == REG_SZ && value_data_size == 0)
864     {
865       p_value->ptr = g_strdup ("");
866       g_free (value_namew);
867       return TRUE;
868     }
869
870   if (p_value->type == REG_DWORD)
871     /* REG_DWORD is inlined */
872     buffer = (void *)&p_value->dword;
873   else
874     buffer = p_value->ptr = g_malloc (value_data_size);
875
876   result = RegQueryValueExW (hpath, value_namew, 0, NULL, (LPBYTE)buffer, &value_data_size);
877   g_free (value_namew);
878
879   if (result != ERROR_SUCCESS)
880     {
881       handle_read_error (result, path_name, value_name);
882
883       if (p_value->type != REG_DWORD)
884         g_free (buffer);
885
886       return FALSE;
887     }
888
889   if (p_value->type == REG_SZ)
890     {
891       gchar *valueu8 = g_utf16_to_utf8 (p_value->ptr, -1, NULL, NULL, NULL);
892       g_free (p_value->ptr);
893       p_value->ptr = valueu8;
894     }
895
896   return TRUE;
897 }
898
899 static GVariant *
900 g_registry_settings_backend_read (GSettingsBackend   *backend,
901                                   const gchar        *key_name,
902                                   const GVariantType *expected_type,
903                                   gboolean            default_value)
904 {
905   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
906   GNode *cache_node;
907   RegistryValue registry_value;
908   GVariant *gsettings_value = NULL;
909   gchar *gsettings_type;
910
911   g_return_val_if_fail (expected_type != NULL, NULL);
912
913   if (default_value)
914     return NULL;
915
916   /* Simply read from the cache, which is updated from the registry by the
917    * watch thread as soon as changes can propagate. Any changes not yet in the
918    * cache will have the 'changed' signal emitted after this function returns.
919    */
920   EnterCriticalSection (self->cache_lock);
921   cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
922   LeaveCriticalSection (self->cache_lock);
923
924   trace ("Reading key %s, cache node %x\n", key_name, cache_node);
925
926   /* Maybe it's not set, we can return to default */
927   if (cache_node == NULL)
928     return NULL;
929
930   trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem *)cache_node->data)->value));
931
932   registry_value = ((RegistryCacheItem *)cache_node->data)->value;
933
934   gsettings_type = g_variant_type_dup_string (expected_type);
935
936   /* The registry is user-editable, so we need to be fault-tolerant here. */
937   switch (gsettings_type[0])
938     {
939     case 'b':
940     case 'y':
941     case 'n':
942     case 'q':
943     case 'i':
944     case 'u':
945       if (registry_value.type == REG_DWORD)
946         gsettings_value = g_variant_new (gsettings_type, registry_value.dword);
947       break;
948
949     case 't':
950     case 'x':
951       if (registry_value.type == REG_QWORD)
952         {
953           DWORDLONG qword_value = *(DWORDLONG *)registry_value.ptr;
954           gsettings_value = g_variant_new (gsettings_type, qword_value);
955         }
956       break;
957
958     default:
959       if (registry_value.type == REG_SZ)
960         {
961           if (gsettings_type[0] == 's')
962             gsettings_value = g_variant_new_string ((char *)registry_value.ptr);
963           else
964             {
965               GError *error = NULL;
966
967               gsettings_value = g_variant_parse (expected_type, registry_value.ptr,
968                                                  NULL, NULL, &error);
969
970               if (error != NULL)
971                 g_message ("gregistrysettingsbackend: error parsing key %s: %s",
972                            key_name, error->message);
973             }
974         }
975         break;
976     }
977
978   g_free (gsettings_type);
979
980   return gsettings_value;
981 }
982
983
984 typedef struct
985 {
986   GRegistrySettingsBackend *self;
987   HKEY hroot;
988 } RegistryWrite;
989
990 static gboolean
991 g_registry_settings_backend_write_one (const char *key_name,
992                                        GVariant   *variant,
993                                        gpointer    user_data)
994 {
995   GRegistrySettingsBackend *self;
996   RegistryWrite *action;
997   RegistryValue value;
998   HKEY hroot;
999   HKEY hpath;
1000   gchar *path_name;
1001   gunichar2 *path_namew;
1002   gchar *value_name = NULL;
1003   gunichar2 *value_namew;
1004   DWORD value_data_size;
1005   LPVOID value_data;
1006   gunichar2 *value_dataw;
1007   LONG result;
1008   GNode *node;
1009   gboolean changed;
1010   const gchar *type_string;
1011
1012   type_string = g_variant_get_type_string (variant);
1013   action = user_data;
1014   self = G_REGISTRY_SETTINGS_BACKEND (action->self);
1015   hroot = action->hroot;
1016
1017   value.type = REG_NONE;
1018   value.ptr = NULL;
1019
1020   switch (type_string[0])
1021     {
1022     case 'b':
1023     case 'y':
1024     case 'n':
1025     case 'q':
1026     case 'i':
1027     case 'u':
1028       value.type = REG_DWORD;
1029       value.dword = g_variant_get_as_dword (variant);
1030       value_data_size = 4;
1031       value_data = &value.dword;
1032       break;
1033
1034     case 'x':
1035     case 't':
1036       value.type = REG_QWORD;
1037       value.ptr = g_malloc (8);
1038       *(DWORDLONG *)value.ptr = g_variant_get_as_qword (variant);
1039       value_data_size = 8;
1040       value_data = value.ptr;
1041       break;
1042
1043     default:
1044       value.type = REG_SZ;
1045       if (type_string[0] == 's')
1046         {
1047           gsize length;
1048           value.ptr = g_strdup (g_variant_get_string (variant, &length));
1049           value_data_size = length + 1;
1050           value_data = value.ptr;
1051         }
1052       else
1053         {
1054           GString *value_string;
1055           value_string = g_variant_print_string (variant, NULL, FALSE);
1056           value_data_size = value_string->len + 1;
1057           value.ptr = value_data = g_string_free (value_string, FALSE);
1058         }
1059       break;
1060     }
1061
1062   /* First update the cache, because the value may not have changed and we can
1063    * save a write.
1064    *
1065    * If 'value' has changed then its memory will not be freed by update_node(),
1066    * because it will be stored in the node.
1067    */
1068   EnterCriticalSection (self->cache_lock);
1069   node = registry_cache_get_node_for_key (self->cache_root, key_name, TRUE);
1070   changed = registry_cache_update_node (node, value);
1071   LeaveCriticalSection (self->cache_lock);
1072
1073   if (!changed)
1074     return FALSE;
1075
1076   /* Block the next notification to any watch points above this location,
1077    * because they will each get triggered on a change that is already updated
1078    * in the cache.
1079    */
1080   registry_cache_block_notification (node);
1081
1082   path_name = parse_key (key_name, NULL, &value_name);
1083
1084   trace ("Set key: %s / %s\n", path_name, value_name);
1085
1086   path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1087
1088   /* Store the value in the registry */
1089   result = RegCreateKeyExW (hroot, path_namew, 0, NULL, 0, KEY_WRITE, NULL, &hpath, NULL);
1090   if (result != ERROR_SUCCESS)
1091     {
1092       g_message_win32_error (result, "gregistrysettingsbackend: opening key %s failed",
1093                              path_name + 1);
1094       registry_value_free (value);
1095       g_free (path_namew);
1096       g_free (path_name);
1097       return FALSE;
1098     }
1099
1100   g_free (path_namew);
1101
1102   value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
1103
1104   value_dataw = NULL;
1105
1106   switch (type_string[0])
1107     {
1108     case 'b':
1109     case 'y':
1110     case 'n':
1111     case 'q':
1112     case 'i':
1113     case 'u':
1114     case 'x':
1115     case 't':
1116       break;
1117     default:
1118       value_dataw = g_utf8_to_utf16 (value_data, -1, NULL, NULL, NULL);
1119       value_data = value_dataw;
1120       value_data_size = (DWORD)((wcslen (value_data) + 1) * sizeof (gunichar2));
1121       break;
1122     }
1123
1124   result = RegSetValueExW (hpath, value_namew, 0, value.type, value_data, value_data_size);
1125
1126   if (result != ERROR_SUCCESS)
1127     g_message_win32_error (result, "gregistrysettingsbackend: setting value %s\\%s\\%s\\%s failed.\n",
1128                            predefined_key_to_string (self->base_key),
1129                            self->base_path, path_name, value_name);
1130
1131   /* If the write fails then it will seem like the value has changed until the
1132    * next execution (because we wrote to the cache first). There's no reason
1133    * for it to fail unless something is weirdly broken, however.
1134    */
1135
1136   RegCloseKey (hpath);
1137   g_free (path_name);
1138   g_free (value_namew);
1139   g_free (value_dataw);
1140
1141   return FALSE;
1142 }
1143
1144 /* The dconf write policy is to do the write while making out it succeeded,
1145  * and then backtrack if it didn't. The registry functions are synchronous so
1146  * we can't do that. */
1147
1148 static gboolean
1149 g_registry_settings_backend_write (GSettingsBackend *backend,
1150                                    const gchar      *key_name,
1151                                    GVariant         *value,
1152                                    gpointer          origin_tag)
1153 {
1154   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1155   LONG result;
1156   HKEY hroot;
1157   RegistryWrite action;
1158
1159   result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
1160                             KEY_WRITE, NULL, &hroot, NULL);
1161   if (result != ERROR_SUCCESS)
1162     {
1163       trace ("Error opening/creating key %s\\%s.\n",
1164              predefined_key_to_string (self->base_key),
1165              self->base_path);
1166       return FALSE;
1167     }
1168
1169   action.self = self;
1170   action.hroot = hroot;
1171   g_registry_settings_backend_write_one (key_name, value, &action);
1172   g_settings_backend_changed (backend, key_name, origin_tag);
1173
1174   RegCloseKey (hroot);
1175
1176   return TRUE;
1177 }
1178
1179 static gboolean
1180 g_registry_settings_backend_write_tree (GSettingsBackend *backend,
1181                                         GTree            *values,
1182                                         gpointer          origin_tag)
1183 {
1184   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1185   LONG result;
1186   HKEY hroot;
1187   RegistryWrite action;
1188
1189   result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
1190                             KEY_WRITE, NULL, &hroot, NULL);
1191   if (result != ERROR_SUCCESS)
1192     {
1193       trace ("Error opening/creating key %s\\%s.\n",
1194              predefined_key_to_string (self->base_key),
1195              self->base_path);
1196       return FALSE;
1197     }
1198
1199   action.self =  self;
1200   action.hroot = hroot;
1201   g_tree_foreach (values, (GTraverseFunc)g_registry_settings_backend_write_one,
1202                   &action);
1203
1204   g_settings_backend_changed_tree (backend, values, origin_tag);
1205   RegCloseKey (hroot);
1206
1207   return TRUE;
1208 }
1209
1210 static void
1211 g_registry_settings_backend_reset (GSettingsBackend *backend,
1212                                    const gchar      *key_name,
1213                                    gpointer          origin_tag)
1214 {
1215   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1216   gchar *path_name;
1217   gunichar2 *path_namew;
1218   gchar *value_name = NULL;
1219   gunichar2 *value_namew;
1220   GNode *cache_node;
1221   LONG result;
1222   HKEY hpath;
1223
1224   /* Remove from cache */
1225   EnterCriticalSection (self->cache_lock);
1226   cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
1227   if (cache_node)
1228     registry_cache_destroy_tree (cache_node, self->watch);
1229   LeaveCriticalSection (self->cache_lock);
1230
1231   /* Remove from the registry */
1232   path_name = parse_key (key_name, self->base_path, &value_name);
1233   path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1234
1235   result = RegOpenKeyExW (self->base_key, path_namew, 0, KEY_SET_VALUE, &hpath);
1236   g_free (path_namew);
1237
1238   if (result != ERROR_SUCCESS)
1239     {
1240       g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
1241                              predefined_key_to_string (self->base_key),
1242                              path_name);
1243       g_free (path_name);
1244       return;
1245     }
1246
1247   value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
1248
1249   result = RegDeleteValueW (hpath, value_namew);
1250   g_free (value_namew);
1251   RegCloseKey (hpath);
1252
1253   if (result != ERROR_SUCCESS)
1254     {
1255       g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
1256                              predefined_key_to_string (self->base_key),
1257                              path_name);
1258       g_free (path_name);
1259       return;
1260     }
1261
1262   g_free (path_name);
1263
1264   g_settings_backend_changed (backend, key_name, origin_tag);
1265 }
1266
1267 static gboolean
1268 g_registry_settings_backend_get_writable (GSettingsBackend *backend,
1269                                           const gchar      *key_name)
1270 {
1271   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1272   gchar *path_name;
1273   gunichar2 *path_namew;
1274   gchar *value_name = NULL;
1275   HKEY hpath;
1276   LONG result;
1277
1278   path_name = parse_key (key_name, self->base_path, &value_name);
1279   path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1280
1281   /* Note: we create the key if it wasn't created yet, but it is not much
1282    * of a problem since at the end of the day we have to create it anyway
1283    * to read or to write from it
1284    */
1285   result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0,
1286                             KEY_WRITE, NULL, &hpath, NULL);
1287   g_free (path_namew);
1288
1289   if (result != ERROR_SUCCESS)
1290     {
1291       trace ("Error opening/creating key to check writability: %s\\%s.\n",
1292              predefined_key_to_string (self->base_key),
1293              path_name);
1294       g_free (path_name);
1295
1296       return FALSE;
1297     }
1298
1299   g_free (path_name);
1300   RegCloseKey (hpath);
1301
1302   return TRUE;
1303 }
1304
1305 /********************************************************************************
1306  * Spot-the-difference engine
1307  ********************************************************************************/
1308
1309 static void
1310 _free_watch (WatchThreadState *self,
1311              guint             index,
1312              GNode            *cache_node);
1313
1314 static void
1315 registry_cache_item_reset_readable (GNode    *node,
1316                                     gpointer  data)
1317 {
1318   RegistryCacheItem *item = node->data;
1319   item->readable = FALSE;
1320 }
1321
1322 /* Delete a node and any children, for when it has been deleted from the registry */
1323 static void
1324 registry_cache_destroy_tree (GNode            *node,
1325                              WatchThreadState *self)
1326 {
1327   RegistryCacheItem *item = node->data;
1328
1329   g_node_children_foreach (node, G_TRAVERSE_ALL,
1330                            (GNodeForeachFunc)registry_cache_destroy_tree, self);
1331
1332   if (item->subscription_count > 0)
1333     {
1334       guint i;
1335
1336       /* There must be some watches active if this node is a watch point */
1337       g_warn_if_fail (self->cache_nodes->len > 1);
1338
1339       /* This is a watch point that has been deleted. Let's free the watch! */
1340       for (i = 1; i < self->cache_nodes->len; i++)
1341         {
1342           if (g_ptr_array_index (self->cache_nodes, i) == node)
1343             break;
1344         }
1345
1346       if (i >= self->cache_nodes->len)
1347         g_warning ("watch thread: a watch point was deleted, but unable to "
1348                    "find '%s' in the list of %i watch nodes\n", item->name,
1349                    self->cache_nodes->len - 1);
1350       else
1351         {
1352           _free_watch (self, i, node);
1353           g_atomic_int_inc (&self->watches_remaining);
1354         }
1355     }
1356   registry_cache_item_free (node->data);
1357   g_node_destroy (node);
1358 }
1359
1360 /* One of these is sent down the pipe when something happens in the registry. */
1361 typedef struct
1362 {
1363   GRegistrySettingsBackend *self;
1364   gchar *prefix;          /* prefix is a gsettings path, all items are subkeys of this. */
1365   GPtrArray *items;       /* each item is a subkey below prefix that has changed. */
1366 } RegistryEvent;
1367
1368 typedef struct
1369 {
1370   RegistryEvent *event;
1371   gchar *current_key_name;
1372 } DeletedItemData;
1373
1374 static void
1375 mark_all_subkeys_as_changed (GNode    *node,
1376                              gpointer  data)
1377 {
1378   RegistryCacheItem *item = node->data;
1379   DeletedItemData *item_data = data;
1380
1381   if (item_data->current_key_name == NULL)
1382     item_data->current_key_name = g_strdup (item->name);
1383   else
1384     {
1385       gchar *name;
1386
1387       name = g_build_path ("/", item_data->current_key_name, item->name, NULL);
1388       g_free (item_data->current_key_name);
1389       item_data->current_key_name = name;
1390     }
1391
1392   /* Iterate until we find an item that is a value */
1393   if (item->value.type == REG_NONE)
1394     g_node_children_foreach (node, G_TRAVERSE_ALL,
1395                              mark_all_subkeys_as_changed, data);
1396   else
1397     g_ptr_array_add (item_data->event->items, item_data->current_key_name);
1398 }
1399
1400 static void
1401 registry_cache_remove_deleted (GNode    *node,
1402                                gpointer  data)
1403 {
1404   RegistryCacheItem *item = node->data;
1405   RegistryEvent *event = data;
1406
1407   if (!item->readable)
1408     {
1409       DeletedItemData item_data;
1410
1411       item_data.event = event;
1412       item_data.current_key_name = NULL;
1413
1414       mark_all_subkeys_as_changed (node, &item_data);
1415       registry_cache_destroy_tree (node, event->self->watch);
1416     }
1417 }
1418
1419 /* Update cache from registry, and optionally report on the changes.
1420  *
1421  * This function is sometimes called from the watch thread, with no locking. It
1422  * does call g_registry_settings_backend functions, but this is okay because they only
1423  * access self->base which is constant.
1424  *
1425  * When looking at this code bear in mind the terminology: in the registry, keys
1426  * are containers that contain values, and other keys. Keys have a 'default'
1427  * value which we always ignore.
1428  *
1429  * n_parent_watches: a counter used to set the reference count of any new nodes
1430  *                   that are created - they should have as many references as
1431  *                   there are notifications that are watching them.
1432  */
1433 static void
1434 registry_cache_update (GRegistrySettingsBackend *self,
1435                        HKEY                      hpath,
1436                        const gchar              *prefix,
1437                        const gchar              *partial_key_name,
1438                        GNode                    *cache_node,
1439                        int                       n_watches,
1440                        RegistryEvent            *event)
1441 {
1442   gunichar2 bufferw[MAX_KEY_NAME_LENGTH + 1];
1443   gchar *buffer;
1444   gchar *key_name;
1445   gint i;
1446   LONG result;
1447   RegistryCacheItem *item;
1448
1449   item = cache_node->data;
1450
1451   if (item->subscription_count > 0)
1452     n_watches++;
1453
1454   /* prefix is the level that all changes occur below; partial_key_name should
1455    * be NULL on the first call to this function */
1456   key_name = g_build_path ("/", prefix, partial_key_name, NULL);
1457
1458   trace ("registry cache update: %s. Node %x has %i children\n", key_name,
1459          cache_node, g_node_n_children (cache_node));
1460
1461   /* Start by zeroing 'readable' flag. When the registry traversal is done, any unreadable nodes
1462    * must have been deleted from the registry.
1463    */
1464   g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1465                            registry_cache_item_reset_readable, NULL);
1466
1467   /* Recurse into each subpath at the current level, if any */
1468   i = 0;
1469   while (1)
1470     {
1471       DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
1472       HKEY  hsubpath;
1473
1474       result = RegEnumKeyExW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
1475       if (result != ERROR_SUCCESS)
1476         break;
1477
1478       result = RegOpenKeyExW (hpath, bufferw, 0, KEY_READ, &hsubpath);
1479       if (result == ERROR_SUCCESS)
1480         {
1481           GNode *subkey_node;
1482           RegistryCacheItem *child_item;
1483           gchar *new_partial_key_name;
1484
1485           buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
1486           if (buffer == NULL)
1487             continue;
1488
1489           subkey_node = registry_cache_find_immediate_child (cache_node, buffer);
1490           if (subkey_node == NULL)
1491             {
1492               RegistryValue null_value = {REG_NONE, {0}};
1493               subkey_node = registry_cache_add_item (cache_node, buffer,
1494                                                      null_value, n_watches);
1495             }
1496
1497           new_partial_key_name = g_build_path ("/", partial_key_name, buffer, NULL);
1498           registry_cache_update (self, hsubpath, prefix, new_partial_key_name,
1499                                  subkey_node, n_watches, event);
1500           g_free (new_partial_key_name);
1501
1502           child_item = subkey_node->data;
1503           child_item->readable = TRUE;
1504
1505           g_free (buffer);
1506           RegCloseKey (hsubpath);
1507         }
1508     }
1509
1510   if (result != ERROR_NO_MORE_ITEMS)
1511     g_message_win32_error (result, "gregistrysettingsbackend: error enumerating subkeys for cache.");
1512
1513   /* Enumerate each value at 'path' and check if it has changed */
1514   i = 0;
1515   while (1)
1516     {
1517       DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
1518       GNode *cache_child_node;
1519       RegistryCacheItem *child_item;
1520       RegistryValue value;
1521       gboolean changed = FALSE;
1522
1523       result = RegEnumValueW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
1524       if (result != ERROR_SUCCESS)
1525         break;
1526
1527       buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
1528
1529       if (buffer == NULL || buffer[0] == 0)
1530         {
1531           /* This is the key's 'default' value, for which we have no use. */
1532           g_free (buffer);
1533           continue;
1534         }
1535
1536       cache_child_node = registry_cache_find_immediate_child (cache_node, buffer);
1537
1538       if (!registry_read (hpath, key_name, buffer, &value))
1539         {
1540           g_free (buffer);
1541           continue;
1542         }
1543
1544       trace ("\tgot value %s for %s, node %x\n",
1545              registry_value_dump (value), buffer, cache_child_node);
1546
1547       if (cache_child_node == NULL)
1548         {
1549           /* This is a new value */
1550           cache_child_node = registry_cache_add_item (cache_node, buffer, value,
1551                                                       n_watches);
1552           changed = TRUE;
1553         }
1554       else
1555         {
1556          /* For efficiency, instead of converting every value back to a GVariant to
1557           * compare it, we compare them as registry values (integers, or string
1558           * representations of the variant). The spurious change notifications that may
1559           * result should not be a big issue.
1560           *
1561           * Note that 'value' is swallowed or freed.
1562           */
1563           changed = registry_cache_update_node (cache_child_node, value);
1564         }
1565
1566       child_item = cache_child_node->data;
1567       child_item->readable = TRUE;
1568       if (changed && event != NULL)
1569         {
1570           gchar *item_path;
1571
1572           if (partial_key_name == NULL)
1573             item_path = g_strdup (buffer);
1574           else
1575             item_path = g_build_path ("/", partial_key_name, buffer, NULL);
1576
1577           g_ptr_array_add (event->items, item_path);
1578         }
1579
1580       g_free (buffer);
1581     }
1582
1583   if (result != ERROR_NO_MORE_ITEMS)
1584     g_message_win32_error (result, "gregistrysettingsbackend: error enumerating values for cache");
1585
1586   /* Any nodes now left unreadable must have been deleted, remove them from cache */
1587   g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1588                            registry_cache_remove_deleted, event);
1589
1590   trace ("registry cache update complete.\n");
1591
1592   g_free (key_name);
1593 }
1594
1595 /***********************************************************************************
1596  * Thread to watch for registry change events
1597  ***********************************************************************************/
1598
1599 /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
1600 static DWORD
1601 registry_watch_key (HKEY   hpath,
1602                     HANDLE event)
1603 {
1604   return RegNotifyChangeKeyValue (hpath, TRUE,
1605                                   REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
1606                                   event, TRUE);
1607 }
1608
1609 /* This handler runs in the main thread to emit the changed signals */
1610 static gboolean
1611 watch_handler (RegistryEvent *event)
1612 {
1613   trace ("Watch handler: got event in %s, items %i.\n", event->prefix, event->items->len);
1614
1615   /* GSettings requires us to NULL-terminate the array. */
1616   g_ptr_array_add (event->items, NULL);
1617   g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event->self), event->prefix,
1618                                    (gchar const **)event->items->pdata, NULL);
1619
1620   g_ptr_array_free (event->items, TRUE);
1621   g_free (event->prefix);
1622   g_object_unref (event->self);
1623   g_slice_free (RegistryEvent, event);
1624
1625   return G_SOURCE_REMOVE;
1626 }
1627
1628 static void
1629 _free_watch (WatchThreadState *self,
1630              guint             index,
1631              GNode            *cache_node)
1632 {
1633   HKEY hpath;
1634   HANDLE cond;
1635   gchar *prefix;
1636
1637   g_return_if_fail (index > 0 && index < self->events->len);
1638
1639   cond = g_ptr_array_index (self->events, index);
1640   hpath = g_ptr_array_index (self->handles, index);
1641   prefix = g_ptr_array_index (self->prefixes, index);
1642
1643   trace ("Freeing watch %i [%s]\n", index, prefix);
1644
1645   /* These can be NULL if the watch was already dead, this can happen when eg.
1646    * a key is deleted but GSettings is still subscribed to it - the watch is
1647    * kept alive so that the unsubscribe function works properly, but does not
1648    * do anything.
1649    */
1650   if (hpath != NULL)
1651     RegCloseKey (hpath);
1652
1653   if (cache_node != NULL)
1654     {
1655       //registry_cache_dump (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_root, NULL);
1656       registry_cache_unref_tree (cache_node);
1657     }
1658
1659   CloseHandle (cond);
1660   g_free (prefix);
1661
1662   /* As long as we remove from each array at the same time, it doesn't matter that
1663    * their orders get messed up - they all get messed up the same.
1664    */
1665   g_ptr_array_remove_index_fast (self->handles, index);
1666   g_ptr_array_remove_index_fast (self->events, index);
1667   g_ptr_array_remove_index_fast (self->prefixes, index);
1668   g_ptr_array_remove_index_fast (self->cache_nodes, index);
1669 }
1670
1671 static void
1672 watch_thread_handle_message (WatchThreadState *self)
1673 {
1674   switch (self->message.type)
1675     {
1676     case WATCH_THREAD_NONE:
1677       trace ("watch thread: you woke me up for nothin', man!");
1678       break;
1679
1680     case WATCH_THREAD_ADD_WATCH:
1681       {
1682         RegistryWatch *watch = &self->message.watch;
1683         LONG result;
1684
1685         result = registry_watch_key (watch->hpath, watch->event);
1686
1687         if (result == ERROR_SUCCESS)
1688           {
1689             g_ptr_array_add (self->events, watch->event);
1690             g_ptr_array_add (self->handles, watch->hpath);
1691             g_ptr_array_add (self->prefixes, watch->prefix);
1692             g_ptr_array_add (self->cache_nodes, watch->cache_node);
1693
1694             trace ("watch thread: new watch on %s, %i total\n", watch->prefix,
1695                    self->events->len);
1696           }
1697         else
1698           {
1699             g_message_win32_error (result, "watch thread: could not watch %s", watch->prefix);
1700
1701             CloseHandle (watch->event);
1702             RegCloseKey (watch->hpath);
1703             g_free (watch->prefix);
1704             registry_cache_unref_tree (watch->cache_node);
1705           }
1706         break;
1707       }
1708
1709     case WATCH_THREAD_REMOVE_WATCH:
1710       {
1711         GNode *cache_node;
1712         RegistryCacheItem *cache_item;
1713         guint i;
1714
1715         for (i = 1; i < self->prefixes->len; i++)
1716           {
1717             if (strcmp (g_ptr_array_index (self->prefixes, i),
1718                         self->message.watch.prefix) == 0)
1719               break;
1720           }
1721
1722         if (i >= self->prefixes->len)
1723           {
1724             /* Don't make a fuss if the prefix is not being watched because
1725              * maybe the path was deleted so we removed the watch.
1726              */
1727             trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
1728                    self->message.watch.prefix, self->prefixes->len);
1729             g_free (self->message.watch.prefix);
1730             break;
1731           }
1732
1733         cache_node = g_ptr_array_index (self->cache_nodes, i);
1734
1735         trace ("watch thread: unsubscribe: freeing node %p, prefix %s, index %i\n",
1736                cache_node, self->message.watch.prefix, i);
1737
1738         if (cache_node != NULL)
1739           {
1740             cache_item = cache_node->data;
1741
1742             /* There may be more than one GSettings object subscribed to this
1743              * path, only free the watch when the last one unsubscribes.
1744              */
1745             cache_item->subscription_count--;
1746             if (cache_item->subscription_count > 0)
1747               break;
1748           }
1749
1750         _free_watch (self, i, cache_node);
1751         g_free (self->message.watch.prefix);
1752
1753         g_atomic_int_inc (&self->watches_remaining);
1754         break;
1755       }
1756
1757     case WATCH_THREAD_STOP:
1758       {
1759         guint i;
1760
1761         /* Free any remaining cache and watch handles */
1762         for (i = 1; i < self->events->len; i++)
1763           _free_watch (self, i, g_ptr_array_index (self->cache_nodes, i));
1764
1765         SetEvent (self->message_received_event);
1766         ExitThread (0);
1767       }
1768     }
1769
1770   self->message.type = WATCH_THREAD_NONE;
1771   SetEvent (self->message_received_event);
1772 }
1773
1774 /* Thread which watches for win32 registry events */
1775 static DWORD WINAPI
1776 watch_thread_function (LPVOID parameter)
1777 {
1778   WatchThreadState *self = (WatchThreadState *)parameter;
1779   DWORD result;
1780
1781   self->events = g_ptr_array_new ();
1782   self->handles = g_ptr_array_new ();
1783   self->prefixes = g_ptr_array_new ();
1784   self->cache_nodes = g_ptr_array_new ();
1785   g_ptr_array_add (self->events, self->message_sent_event);
1786   g_ptr_array_add (self->handles, NULL);
1787   g_ptr_array_add (self->prefixes, NULL);
1788   g_ptr_array_add (self->cache_nodes, NULL);
1789
1790   while (1)
1791     {
1792       trace ("watch thread: going to sleep; %i events watched.\n", self->events->len);
1793       result = WaitForMultipleObjects (self->events->len, self->events->pdata, FALSE, INFINITE);
1794
1795       if (result == WAIT_OBJECT_0)
1796         {
1797           /* A message to you. The sender (main thread) will block until we signal the received
1798            * event, so there should be no danger of it sending another before we receive the
1799            * first.
1800            */
1801           watch_thread_handle_message (self);
1802         }
1803       else if (result > WAIT_OBJECT_0 && result <= WAIT_OBJECT_0 + self->events->len)
1804         {
1805           HKEY hpath;
1806           HANDLE cond;
1807           gchar *prefix;
1808           GNode *cache_node;
1809           RegistryCacheItem *cache_item;
1810           RegistryEvent *event;
1811           gint notify_index;
1812
1813           /* One of our notifications has triggered. All we know is which one, and which key
1814            * this is for. We do most of the processing here, because we may as well. If the
1815            * registry changes further while we are processing it doesn't matter - we will then
1816            * receive another change notification from the OS anyway.
1817            */
1818           notify_index = result - WAIT_OBJECT_0;
1819           hpath = g_ptr_array_index (self->handles, notify_index);
1820           cond = g_ptr_array_index (self->events, notify_index);
1821           prefix = g_ptr_array_index (self->prefixes, notify_index);
1822           cache_node = g_ptr_array_index (self->cache_nodes, notify_index);
1823
1824           trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index, prefix);
1825
1826           if (cache_node == NULL)
1827             {
1828               /* This path has been deleted */
1829               trace ("Notify received on a path that was deleted\n");
1830               continue;
1831             }
1832
1833           /* Firstly we need to reapply for the notification, because (what a
1834            * sensible API) we won't receive any more. MSDN is pretty
1835            * inconsistent on this matter:
1836            *   http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
1837            *   http://support.microsoft.com/kb/236570
1838            * But my tests (on Windows XP SP3) show that we need to reapply
1839            * each time.
1840            */
1841           result = registry_watch_key (hpath, cond);
1842
1843           if (result != ERROR_SUCCESS)
1844             {
1845               /* Watch failed, most likely because the key has just been
1846                * deleted. Free the watch and unref the cache nodes.
1847                */
1848              if (result != ERROR_KEY_DELETED)
1849                g_message_win32_error (result, "watch thread: failed to watch %s", prefix);
1850
1851              _free_watch (self, notify_index, cache_node);
1852              g_atomic_int_inc (&self->watches_remaining);
1853              continue;
1854             }
1855
1856           /* The notification may have been blocked because we just changed
1857            * some data ourselves.
1858            */
1859           cache_item = cache_node->data;
1860           if (cache_item->block_count)
1861             {
1862               cache_item->block_count--;
1863               trace ("Watch thread: notify blocked at %s\n", prefix);
1864               continue;
1865             }
1866
1867           /* Now we update our stored cache from registry data, and find which keys have
1868            * actually changed. If more changes happen while we are processing, we will get
1869            * another event because we have reapplied for change notifications already.
1870            *
1871            * Working here rather than in the main thread is preferable because the UI is less
1872            * likely to block (only when changing notification subscriptions).
1873            */
1874           event = g_slice_new (RegistryEvent);
1875           event->self = G_REGISTRY_SETTINGS_BACKEND (g_object_ref (self->owner));
1876           event->prefix = g_strdup (prefix);
1877           event->items = g_ptr_array_new_with_free_func (g_free);
1878
1879           EnterCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
1880           registry_cache_update (G_REGISTRY_SETTINGS_BACKEND (self->owner), hpath,
1881                                  prefix, NULL, cache_node, 0, event);
1882           LeaveCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
1883
1884           if (event->items->len > 0)
1885             g_idle_add ((GSourceFunc) watch_handler, event);
1886           else
1887             {
1888               g_object_unref (event->self);
1889               g_free (event->prefix);
1890               g_ptr_array_free (event->items, TRUE);
1891               g_slice_free (RegistryEvent, event);
1892             }
1893         }
1894       else
1895         {
1896           /* God knows what has happened */
1897           g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
1898         }
1899     }
1900
1901   return -1;
1902 }
1903
1904 static gboolean
1905 watch_start (GRegistrySettingsBackend *self)
1906 {
1907   WatchThreadState *watch;
1908
1909   g_return_val_if_fail (self->watch == NULL, FALSE);
1910
1911   watch = g_slice_new (WatchThreadState);
1912   watch->owner = G_SETTINGS_BACKEND (self);
1913
1914   watch->watches_remaining = MAX_WATCHES;
1915
1916   watch->message_lock = g_slice_new (CRITICAL_SECTION);
1917   InitializeCriticalSection (watch->message_lock);
1918   watch->message_sent_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1919   watch->message_received_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1920   if (watch->message_sent_event == NULL || watch->message_received_event == NULL)
1921     {
1922       g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create sync objects.");
1923       goto fail;
1924     }
1925
1926   /* Use a small stack to make the thread more lightweight. */
1927   watch->thread = CreateThread (NULL, 1024, watch_thread_function, watch, 0, NULL);
1928   if (watch->thread == NULL)
1929     {
1930       g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create notify watch thread.");
1931       goto fail;
1932     }
1933
1934   self->watch = watch;
1935
1936   return TRUE;
1937
1938 fail:
1939   DeleteCriticalSection (watch->message_lock);
1940   g_slice_free (CRITICAL_SECTION, watch->message_lock);
1941   if (watch->message_sent_event != NULL)
1942     CloseHandle (watch->message_sent_event);
1943   if (watch->message_received_event != NULL)
1944     CloseHandle (watch->message_received_event);
1945   g_slice_free (WatchThreadState, watch);
1946
1947   return FALSE;
1948 }
1949
1950 /* This function assumes you hold the message lock! */
1951 static void
1952 watch_stop_unlocked (GRegistrySettingsBackend *self)
1953 {
1954   WatchThreadState *watch = self->watch;
1955   DWORD result;
1956
1957   g_return_if_fail (watch != NULL);
1958
1959   watch->message.type = WATCH_THREAD_STOP;
1960   SetEvent (watch->message_sent_event);
1961
1962   /* This is signalled as soon as the message is received. We must not return
1963    * while the watch thread is still firing off callbacks. Freeing all of the
1964    * memory is done in the watch thread after this is signalled.
1965    */
1966   result = WaitForSingleObject (watch->message_received_event, INFINITE);
1967   if (result != WAIT_OBJECT_0)
1968     {
1969       g_warning ("gregistrysettingsbackend: unable to stop watch thread.");
1970       return;
1971     }
1972
1973   LeaveCriticalSection (watch->message_lock);
1974   DeleteCriticalSection (watch->message_lock);
1975   g_slice_free (CRITICAL_SECTION, watch->message_lock);
1976   CloseHandle (watch->message_sent_event);
1977   CloseHandle (watch->message_received_event);
1978   CloseHandle (watch->thread);
1979   g_slice_free (WatchThreadState, watch);
1980
1981   trace ("\nwatch thread: %x: all data freed.\n", self);
1982   self->watch = NULL;
1983 }
1984
1985 static gboolean
1986 watch_add_notify (GRegistrySettingsBackend *self,
1987                   HANDLE                    event,
1988                   HKEY                      hpath,
1989                   gchar                    *gsettings_prefix)
1990 {
1991   WatchThreadState *watch = self->watch;
1992   GNode *cache_node;
1993   RegistryCacheItem *cache_item;
1994 #ifdef TRACE
1995   DWORD result;
1996 #endif
1997
1998   g_return_val_if_fail (watch != NULL, FALSE);
1999
2000   trace ("watch_add_notify: prefix %s.\n", gsettings_prefix);
2001
2002   /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
2003    * thread we can miss changes while we are caching.
2004    */
2005   EnterCriticalSection (self->cache_lock);
2006   cache_node = registry_cache_get_node_for_key (self->cache_root, gsettings_prefix, TRUE);
2007
2008   if (cache_node == NULL || cache_node->data == NULL)
2009     {
2010       LeaveCriticalSection (self->cache_lock);
2011       g_warn_if_reached ();
2012       return FALSE;
2013     }
2014
2015   cache_item = cache_node->data;
2016
2017   cache_item->subscription_count++;
2018   if (cache_item->subscription_count > 1)
2019     {
2020       trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
2021              gsettings_prefix, cache_item->subscription_count);
2022       LeaveCriticalSection (self->cache_lock);
2023       return FALSE;
2024     }
2025
2026   registry_cache_ref_tree (cache_node);
2027   registry_cache_update (self, hpath, gsettings_prefix, NULL, cache_node, 0, NULL);
2028   //registry_cache_dump (self->cache_root, NULL);
2029   LeaveCriticalSection (self->cache_lock);
2030
2031   EnterCriticalSection (watch->message_lock);
2032   watch->message.type = WATCH_THREAD_ADD_WATCH;
2033   watch->message.watch.event = event;
2034   watch->message.watch.hpath = hpath;
2035   watch->message.watch.prefix = gsettings_prefix;
2036   watch->message.watch.cache_node = cache_node;
2037
2038   SetEvent (watch->message_sent_event);
2039
2040   /* Wait for the received event in return, to avoid sending another message before the first
2041    * one was received. If it takes > 200ms there is a possible race but the worst outcome is
2042    * a notification is ignored.
2043    */
2044 #ifdef TRACE
2045   result =
2046 #endif
2047     WaitForSingleObject (watch->message_received_event, 200);
2048 #ifdef TRACE
2049   if (result != WAIT_OBJECT_0)
2050     trace ("watch thread is slow to respond - notification may not be added.");
2051 #endif
2052
2053   LeaveCriticalSection (watch->message_lock);
2054
2055   return TRUE;
2056 }
2057
2058 static void
2059 watch_remove_notify (GRegistrySettingsBackend *self,
2060                      const gchar              *key_name)
2061 {
2062   WatchThreadState *watch = self->watch;
2063   LONG result;
2064
2065   if (self->watch == NULL)
2066     /* Here we assume that the unsubscribe message is for somewhere that was
2067      * deleted, and so it has already been removed and the watch thread has
2068      * stopped.
2069      */
2070     return;
2071
2072   EnterCriticalSection (watch->message_lock);
2073   watch->message.type = WATCH_THREAD_REMOVE_WATCH;
2074   watch->message.watch.prefix = g_strdup (key_name);
2075
2076   SetEvent (watch->message_sent_event);
2077
2078   /* Wait for the received event in return, to avoid sending another message before the first
2079    * one was received.
2080    */
2081   result = WaitForSingleObject (watch->message_received_event, INFINITE);
2082
2083   if (result != ERROR_SUCCESS)
2084     g_warning ("unsubscribe from %s: message not acknowledged", key_name);
2085
2086   if (g_atomic_int_get (&watch->watches_remaining) >= MAX_WATCHES)
2087     /* Stop it before any new ones can get added and confuse things */
2088     watch_stop_unlocked (self);
2089   else
2090     LeaveCriticalSection (watch->message_lock);
2091 }
2092
2093 /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
2094  * key. Our job is easier because keys and values are separate.
2095  */
2096 static void
2097 g_registry_settings_backend_subscribe (GSettingsBackend *backend,
2098                                        const char       *key_name)
2099 {
2100   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
2101   gchar *path_name;
2102   gunichar2 *path_namew;
2103   gchar *value_name = NULL;
2104   HKEY hpath;
2105   HANDLE event;
2106   LONG result;
2107
2108   if (self->watch == NULL && !watch_start (self))
2109     return;
2110
2111   if (g_atomic_int_dec_and_test (&self->watch->watches_remaining))
2112     {
2113       g_atomic_int_inc (&self->watch->watches_remaining);
2114       g_warning ("subscribe() failed: only %i different paths may be watched.", MAX_WATCHES);
2115       return;
2116     }
2117
2118   path_name = parse_key (key_name, self->base_path, &value_name);
2119
2120   /* Must check for this, otherwise strange crashes occur because the cache
2121    * node that is being watched gets freed. All path names to subscribe must
2122    * end in a slash!
2123    */
2124   if (value_name != NULL && *value_name != 0)
2125     g_warning ("subscribe() failed: path must end in a /, got %s", key_name);
2126
2127   trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name, path_name, value_name, self->watch);
2128
2129   path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
2130   g_free (path_name);
2131
2132   /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
2133    * is almost certainly a new g_settings with this path as base path. */
2134   result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0, KEY_READ, NULL, &hpath,
2135                             NULL);
2136   g_free (path_namew);
2137
2138   if (result != ERROR_SUCCESS)
2139     {
2140       g_message_win32_error (result, "gregistrysettingsbackend: Unable to subscribe to key %s.", key_name);
2141       g_atomic_int_inc (&self->watch->watches_remaining);
2142       return;
2143     }
2144
2145   event = CreateEvent (NULL, FALSE, FALSE, NULL);
2146   if (event == NULL)
2147     {
2148       g_message_win32_error (result, "gregistrysettingsbackend: CreateEvent failed.");
2149       g_atomic_int_inc (&self->watch->watches_remaining);
2150       RegCloseKey (hpath);
2151       return;
2152     }
2153
2154   /* The actual watch is added by the thread, which has to re-subscribe each time it
2155    * receives a change. */
2156   if (!watch_add_notify (self, event, hpath, g_strdup (key_name)))
2157     {
2158       g_atomic_int_inc (&self->watch->watches_remaining);
2159       RegCloseKey (hpath);
2160       CloseHandle (event);
2161     }
2162 }
2163
2164 static void
2165 g_registry_settings_backend_unsubscribe (GSettingsBackend *backend,
2166                                          const char       *key_name)
2167 {
2168   trace ("unsubscribe: %s.\n", key_name);
2169
2170   watch_remove_notify (G_REGISTRY_SETTINGS_BACKEND (backend), key_name);
2171 }
2172
2173 /********************************************************************************
2174  * Object management junk
2175  ********************************************************************************/
2176
2177 static void
2178 g_registry_settings_backend_finalize (GObject *object)
2179 {
2180   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2181   RegistryCacheItem *item;
2182
2183   item = self->cache_root->data;
2184   g_warn_if_fail (item->ref_count == 1);
2185
2186   registry_cache_item_free (item);
2187   g_node_destroy (self->cache_root);
2188
2189   if (self->watch != NULL)
2190     {
2191       EnterCriticalSection (self->watch->message_lock);
2192       watch_stop_unlocked (self);
2193     }
2194
2195   DeleteCriticalSection (self->cache_lock);
2196   g_slice_free (CRITICAL_SECTION, self->cache_lock);
2197
2198   g_free (self->base_path);
2199   g_free (self->base_pathw);
2200 }
2201
2202 static void
2203 g_registry_settings_backend_constructed (GObject *object)
2204 {
2205   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2206
2207   if (self->base_key == NULL || self->base_path == NULL || self->base_pathw == NULL)
2208     {
2209       self->base_key = HKEY_CURRENT_USER;
2210       self->base_path = g_strdup ("Software\\GSettings");
2211       self->base_pathw = g_utf8_to_utf16 (self->base_path, -1, NULL, NULL, NULL);
2212     }
2213 }
2214
2215 static void
2216 g_registry_settings_backend_get_property (GObject    *object,
2217                                           guint       prop_id,
2218                                           GValue     *value,
2219                                           GParamSpec *pspec)
2220 {
2221   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2222
2223   switch ((GRegistrySettingsBackendProperty) prop_id)
2224     {
2225     case PROP_REGISTRY_KEY:
2226       g_value_take_string (value,
2227                            g_strdup_printf ("%s\\%s",
2228                                             predefined_key_to_string (self->base_key),
2229                                             self->base_path));
2230       break;
2231
2232     default:
2233       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2234       break;
2235     }
2236 }
2237
2238 static void
2239 g_registry_settings_backend_set_property (GObject      *object,
2240                                           guint         prop_id,
2241                                           const GValue *value,
2242                                           GParamSpec   *pspec)
2243 {
2244   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2245   const gchar *reg_path;
2246
2247   switch ((GRegistrySettingsBackendProperty) prop_id)
2248     {
2249     case PROP_REGISTRY_KEY:
2250       /* Construct only. */
2251       g_assert (self->base_key == NULL);
2252       g_assert (self->base_path == NULL);
2253       g_assert (self->base_pathw == NULL);
2254
2255       reg_path = g_value_get_string (value);
2256       if (reg_path != NULL)
2257         {
2258           HKEY base_key;
2259           const gchar *base_path = split_registry_path (reg_path, &base_key);
2260
2261           if (base_path != NULL)
2262             {
2263               gunichar2 *base_pathw = g_utf8_to_utf16 (base_path, -1, NULL, NULL, NULL);
2264
2265               if (base_pathw != NULL)
2266                 {
2267                   self->base_key = g_steal_pointer (&base_key);
2268                   self->base_path = g_strdup (base_path);
2269                   self->base_pathw = g_steal_pointer (&base_pathw);
2270                 }
2271               else
2272                 g_warning ("gregistrysettingsbackend: invalid base registry path '%s'", reg_path);
2273             }
2274           else
2275             g_warning ("gregistrysettingsbackend: base registry path '%s' does not start with a valid root key", reg_path);
2276         }
2277       break;
2278
2279     default:
2280       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2281       break;
2282     }
2283 }
2284
2285 static void
2286 g_registry_settings_backend_class_init (GRegistrySettingsBackendClass *class)
2287 {
2288   GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
2289   GObjectClass *object_class = G_OBJECT_CLASS (class);
2290
2291   object_class->finalize = g_registry_settings_backend_finalize;
2292   object_class->constructed = g_registry_settings_backend_constructed;
2293   object_class->get_property = g_registry_settings_backend_get_property;
2294   object_class->set_property = g_registry_settings_backend_set_property;
2295
2296   backend_class->read = g_registry_settings_backend_read;
2297   backend_class->write = g_registry_settings_backend_write;
2298   backend_class->write_tree = g_registry_settings_backend_write_tree;
2299   backend_class->reset = g_registry_settings_backend_reset;
2300   backend_class->get_writable = g_registry_settings_backend_get_writable;
2301   backend_class->subscribe = g_registry_settings_backend_subscribe;
2302   backend_class->unsubscribe = g_registry_settings_backend_unsubscribe;
2303
2304   /**
2305    * GRegistrySettingsBackend:registry-key:
2306    *
2307    * The location where settings are stored in the registry. Must
2308    * start with one of the following:
2309    * - `HKEY_CLASSES_ROOT`
2310    * - `HKEY_CURRENT_CONFIG`
2311    * - `HKEY_CURRENT_USER`
2312    * - `HKEY_LOCAL_MACHINE`
2313    * - `HKEY_USERS`
2314    *
2315    * Defaults to `HKEY_CURRENT_USER\Software\GSettings`.
2316    *
2317    * Since: 2.78
2318    */
2319   g_object_class_install_property (object_class,
2320                                    PROP_REGISTRY_KEY,
2321                                    g_param_spec_string ("registry-key",
2322                                                         NULL, NULL,
2323                                                         "HKEY_CURRENT_USER\\Software\\GSettings",
2324                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
2325                                                         G_PARAM_STATIC_STRINGS));
2326 }
2327
2328 static void
2329 g_registry_settings_backend_init (GRegistrySettingsBackend *self)
2330 {
2331   RegistryCacheItem *item;
2332
2333   item = g_slice_new (RegistryCacheItem);
2334   item->value.type = REG_NONE;
2335   item->value.ptr = NULL;
2336   item->name = g_strdup ("<root>");
2337   item->ref_count = 1;
2338   self->cache_root = g_node_new (item);
2339
2340   self->cache_lock = g_slice_new (CRITICAL_SECTION);
2341   InitializeCriticalSection (self->cache_lock);
2342
2343   self->watch = NULL;
2344 }
2345
2346 /**
2347  * g_registry_settings_backend_new:
2348  * @registry_key: (nullable): the path to the registry key where
2349  *                settings are stored, or %NULL.
2350  *
2351  * If @registry_key is %NULL then the default path
2352  * `HKEY_CURRENT_USER\Software\GSettings` is used.
2353  *
2354  * Returns: (transfer full): a registry-backed #GSettingsBackend
2355  *
2356  * Since: 2.78
2357  **/
2358 GSettingsBackend *
2359 g_registry_settings_backend_new (const gchar *registry_key)
2360 {
2361   g_return_val_if_fail (registry_key == NULL || split_registry_path (registry_key, NULL), NULL);
2362
2363   return G_SETTINGS_BACKEND (g_object_new (G_TYPE_REGISTRY_SETTINGS_BACKEND,
2364                                            "registry-key", registry_key,
2365                                            NULL));
2366 }