summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorPhilip Withnall <philip@tecnocode.co.uk>2018-08-21 15:41:51 +0000
committerPhilip Withnall <philip@tecnocode.co.uk>2018-08-21 15:41:51 +0000
commita060755f30e5c89882b160e7f284eee003a960ec (patch)
tree1765b9bdae5258808f30b421b3c95b9b15e69eef /service
parente960b50696b95f4b035787e9cbceaa549c172c91 (diff)
parent8d76d4881f14af8a78029a89b43ce99cc558a65f (diff)
downloaddconf-a060755f30e5c89882b160e7f284eee003a960ec.tar.gz
Merge branch '1454-gvdb-corruption' into 'master'
service: Allow opening corrupt GVDB files when writing See merge request GNOME/dconf!8
Diffstat (limited to 'service')
-rw-r--r--service/dconf-gvdb-utils.c40
-rw-r--r--service/dconf-gvdb-utils.h2
-rw-r--r--service/dconf-writer.c2
-rw-r--r--service/dconf-writer.h3
-rw-r--r--service/meson.build28
5 files changed, 60 insertions, 15 deletions
diff --git a/service/dconf-gvdb-utils.c b/service/dconf-gvdb-utils.c
index 099a9f3..93a4719 100644
--- a/service/dconf-gvdb-utils.c
+++ b/service/dconf-gvdb-utils.c
@@ -26,12 +26,15 @@
#include "../gvdb/gvdb-builder.h"
#include "../gvdb/gvdb-reader.h"
+#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
#include <string.h>
DConfChangeset *
-dconf_gvdb_utils_read_file (const gchar *filename,
- gboolean *file_missing,
- GError **error)
+dconf_gvdb_utils_read_and_back_up_file (const gchar *filename,
+ gboolean *file_missing,
+ GError **error)
{
DConfChangeset *database;
GError *my_error = NULL;
@@ -57,7 +60,36 @@ dconf_gvdb_utils_read_file (const gchar *filename,
/* Otherwise, we should report errors to prevent ourselves from
* overwriting the database in other situations...
*/
- if (my_error)
+ if (g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_INVAL))
+ {
+ /* Move the database to a backup file, warn and continue with a new
+ * database. The alternative is erroring out and exiting the daemon,
+ * which leaves the user’s session essentially unusable.
+ *
+ * The code to find an unused backup filename is racy, but this is an
+ * error handling path. Who cares. */
+ g_autofree gchar *backup_filename = NULL;
+ guint i;
+
+ for (i = 0;
+ i < G_MAXUINT &&
+ (backup_filename == NULL || g_file_test (backup_filename, G_FILE_TEST_EXISTS));
+ i++)
+ {
+ g_free (backup_filename);
+ backup_filename = g_strdup_printf ("%s~%u", filename, i);
+ }
+
+ if (g_rename (filename, backup_filename) != 0)
+ g_warning ("Error renaming corrupt database from ‘%s’ to ‘%s’: %s",
+ filename, backup_filename, g_strerror (errno));
+ else
+ g_warning ("Database ‘%s’ was corrupt: moved it to ‘%s’ and created an empty replacement",
+ filename, backup_filename);
+
+ g_clear_error (&my_error);
+ }
+ else if (my_error)
{
g_propagate_prefixed_error (error, my_error, "Cannot open dconf database: ");
return NULL;
diff --git a/service/dconf-gvdb-utils.h b/service/dconf-gvdb-utils.h
index 5b3e3a9..7076781 100644
--- a/service/dconf-gvdb-utils.h
+++ b/service/dconf-gvdb-utils.h
@@ -23,7 +23,7 @@
#include "../common/dconf-changeset.h"
-DConfChangeset * dconf_gvdb_utils_read_file (const gchar *filename,
+DConfChangeset * dconf_gvdb_utils_read_and_back_up_file (const gchar *filename,
gboolean *file_missing,
GError **error);
gboolean dconf_gvdb_utils_write_file (const gchar *filename,
diff --git a/service/dconf-writer.c b/service/dconf-writer.c
index 00d34fe..5fb3467 100644
--- a/service/dconf-writer.c
+++ b/service/dconf-writer.c
@@ -107,7 +107,7 @@ dconf_writer_real_begin (DConfWriter *writer,
{
gboolean missing;
- writer->priv->commited_values = dconf_gvdb_utils_read_file (writer->priv->filename, &missing, error);
+ writer->priv->commited_values = dconf_gvdb_utils_read_and_back_up_file (writer->priv->filename, &missing, error);
if (!writer->priv->commited_values)
return FALSE;
diff --git a/service/dconf-writer.h b/service/dconf-writer.h
index a41f115..17360c9 100644
--- a/service/dconf-writer.h
+++ b/service/dconf-writer.h
@@ -20,7 +20,9 @@
#ifndef __dconf_writer_h__
#define __dconf_writer_h__
+#include <glib.h>
#include <gio/gio.h>
+#include <gobject/gobject.h>
#include "../common/dconf-changeset.h"
#include "dconf-generated.h"
@@ -65,6 +67,7 @@ struct _DConfWriter
DConfWriterPrivate *priv;
};
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (DConfWriter, g_object_unref)
GType dconf_writer_get_type (void);
diff --git a/service/meson.build b/service/meson.build
index 618cbd5..35ee23a 100644
--- a/service/meson.build
+++ b/service/meson.build
@@ -11,35 +11,45 @@ configure_file(
install_dir: dbus_session_service_dir,
)
-sources = [
+lib_sources = [
'dconf-blame.c',
'dconf-gvdb-utils.c',
'dconf-keyfile-writer.c',
'dconf-service.c',
'dconf-shm-writer.c',
'dconf-writer.c',
+]
+sources = [
'main.c',
]
-sources += gnome.gdbus_codegen(
+lib_sources += gnome.gdbus_codegen(
'dconf-generated',
dconf_namespace + '.xml',
interface_prefix: dconf_namespace + '.',
namespace: 'DConfDBus',
)
-service_deps = [
- gio_unix_dep,
- libdconf_common_dep,
- libdconf_shm_dep,
- libgvdb_dep,
-]
+libdconf_service = static_library(
+ 'dconf-service',
+ sources: lib_sources,
+ include_directories: top_inc,
+ c_args: dconf_c_args,
+ dependencies: gio_unix_dep,
+ link_with: [
+ libdconf_common,
+ libdconf_shm,
+ libgvdb,
+ ],
+)
executable(
'dconf-service',
sources,
include_directories: top_inc,
- dependencies: service_deps,
+ c_args: dconf_c_args,
+ dependencies: gio_unix_dep,
+ link_with: libdconf_service,
install: true,
install_dir: dconf_libexecdir,
)