Merge branch 'private-data' into 'master'
[dconf.git] / service / dconf-gvdb-utils.c
blob099a9f3579dc95c7d5628f315527a698ab455f33
1 /*
2 * Copyright © 2010 Codethink Limited
3 * Copyright © 2012 Canonical Limited
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the licence, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Ryan Lortie <desrt@desrt.ca>
21 #include "config.h"
23 #include "dconf-gvdb-utils.h"
25 #include "../common/dconf-paths.h"
26 #include "../gvdb/gvdb-builder.h"
27 #include "../gvdb/gvdb-reader.h"
29 #include <string.h>
31 DConfChangeset *
32 dconf_gvdb_utils_read_file (const gchar *filename,
33 gboolean *file_missing,
34 GError **error)
36 DConfChangeset *database;
37 GError *my_error = NULL;
38 GvdbTable *table = NULL;
39 gchar *contents;
40 gsize size;
42 if (g_file_get_contents (filename, &contents, &size, &my_error))
44 GBytes *bytes;
46 bytes = g_bytes_new_take (contents, size);
47 table = gvdb_table_new_from_bytes (bytes, FALSE, &my_error);
48 g_bytes_unref (bytes);
51 /* It is perfectly fine if the file does not exist -- then it's
52 * just empty.
54 if (g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
55 g_clear_error (&my_error);
57 /* Otherwise, we should report errors to prevent ourselves from
58 * overwriting the database in other situations...
60 if (my_error)
62 g_propagate_prefixed_error (error, my_error, "Cannot open dconf database: ");
63 return NULL;
66 /* Only allocate once we know we are in a non-error situation */
67 database = dconf_changeset_new_database (NULL);
69 /* Fill the table up with the initial state */
70 if (table != NULL)
72 gchar **names;
73 gint n_names;
74 gint i;
76 names = gvdb_table_get_names (table, &n_names);
77 for (i = 0; i < n_names; i++)
79 if (dconf_is_key (names[i], NULL))
81 GVariant *value;
83 value = gvdb_table_get_value (table, names[i]);
85 if (value != NULL)
87 dconf_changeset_set (database, names[i], value);
88 g_variant_unref (value);
92 g_free (names[i]);
95 gvdb_table_free (table);
96 g_free (names);
99 if (file_missing)
100 *file_missing = (table == NULL);
102 return database;
105 static GvdbItem *
106 dconf_gvdb_utils_get_parent (GHashTable *table,
107 const gchar *key)
109 GvdbItem *grandparent, *parent;
110 gchar *parent_name;
111 gint len;
113 if (g_str_equal (key, "/"))
114 return NULL;
116 len = strlen (key);
117 if (key[len - 1] == '/')
118 len--;
120 while (key[len - 1] != '/')
121 len--;
123 parent_name = g_strndup (key, len);
124 parent = g_hash_table_lookup (table, parent_name);
126 if (parent == NULL)
128 parent = gvdb_hash_table_insert (table, parent_name);
130 grandparent = dconf_gvdb_utils_get_parent (table, parent_name);
132 if (grandparent != NULL)
133 gvdb_item_set_parent (parent, grandparent);
136 g_free (parent_name);
138 return parent;
141 static gboolean
142 dconf_gvdb_utils_add_key (const gchar *path,
143 GVariant *value,
144 gpointer user_data)
146 GHashTable *gvdb = user_data;
147 GvdbItem *item;
149 g_assert (g_hash_table_lookup (gvdb, path) == NULL);
150 item = gvdb_hash_table_insert (gvdb, path);
151 gvdb_item_set_parent (item, dconf_gvdb_utils_get_parent (gvdb, path));
152 gvdb_item_set_value (item, value);
154 return TRUE;
157 gboolean
158 dconf_gvdb_utils_write_file (const gchar *filename,
159 DConfChangeset *database,
160 GError **error)
162 GHashTable *gvdb;
163 gboolean success;
165 gvdb = gvdb_hash_table_new (NULL, NULL);
166 dconf_changeset_all (database, dconf_gvdb_utils_add_key, gvdb);
167 success = gvdb_table_write_contents (gvdb, filename, FALSE, error);
169 if (!success)
171 gchar *dirname;
173 /* Maybe it failed because the directory doesn't exist. Try
174 * again, after mkdir().
176 dirname = g_path_get_dirname (filename);
177 g_mkdir_with_parents (dirname, 0700);
178 g_free (dirname);
180 g_clear_error (error);
181 success = gvdb_table_write_contents (gvdb, filename, FALSE, error);
184 g_hash_table_unref (gvdb);
186 return success;