[almanah] Moved all the encryption stuff to the SQLiteVFS



commit 430638ec32f99e9276ad8f62ea8197a58afc8470
Author: Álvaro Peña <alvaropg gmail com>
Date:   Sat Sep 27 19:33:02 2014 +0200

    Moved all the encryption stuff to the SQLiteVFS
    
    In another step to complete our own SQLiteVFS, the coded that
    encrypt/decrypt the database has been moved from StorageManager to the
    VFS.
    
    It was required to adapt some APIs and make the call to gpgme_wait in a
    blocker way, due it's required to end the encryption before to close the
    application.
    
    See Bug #659500 - Prevent the unencrypted database from hitting the disk
    https://bugzilla.gnome.org/show_bug.cgi?id=659500

 src/application.c      |   19 +-
 src/export-operation.c |    2 +-
 src/import-operation.c |    2 +-
 src/storage-manager.c  |  466 +-----------------------
 src/storage-manager.h  |    4 +-
 src/vfs.c              |  928 ++++++++++++++++++++++++++++++++++--------------
 6 files changed, 696 insertions(+), 725 deletions(-)
---
diff --git a/src/application.c b/src/application.c
index 0d1f02e..33092f1 100644
--- a/src/application.c
+++ b/src/application.c
@@ -235,12 +235,9 @@ startup (GApplication *application)
 
        /* Open the DB */
        db_filename = g_build_filename (g_get_user_data_dir (), "diary.db", NULL);
-       priv->storage_manager = almanah_storage_manager_new (db_filename, NULL);
+       priv->storage_manager = almanah_storage_manager_new (db_filename);
        g_free (db_filename);
 
-       g_settings_bind (priv->settings, "encryption-key", priv->storage_manager, "encryption-key",
-                        G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY);
-
        if (almanah_storage_manager_connect (priv->storage_manager, &error) == FALSE) {
                GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, 
GTK_BUTTONS_OK,
                                                            _("Error opening database"));
@@ -359,7 +356,7 @@ handle_command_line (GApplication *application, GApplicationCommandLine *command
 }
 
 static void
-storage_manager_disconnected_cb (AlmanahStorageManager *self, const gchar *gpgme_error_message, const gchar 
*warning_message, GtkApplication *application)
+storage_manager_disconnected_cb (__attribute__ ((unused)) AlmanahStorageManager *storage_manager, const 
gchar *gpgme_error_message, const gchar *warning_message, GtkApplication *self)
 {
        if (gpgme_error_message != NULL || warning_message != NULL) {
                GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, 
GTK_BUTTONS_OK,
@@ -377,7 +374,15 @@ storage_manager_disconnected_cb (AlmanahStorageManager *self, const gchar *gpgme
        }
 
        /* Allow the end of the applaction */
-       g_application_release (G_APPLICATION (application));
+       g_application_release (G_APPLICATION (self));
+}
+
+static gboolean
+storage_disconnect_idle_cb (AlmanahStorageManager *storage_manager)
+{
+       almanah_storage_manager_disconnect (storage_manager, NULL);
+
+       return FALSE;
 }
 
 static void
@@ -394,7 +399,7 @@ window_removed (GtkApplication *application, GtkWindow *window)
                g_application_hold (G_APPLICATION (application));
 
                g_signal_connect (priv->storage_manager, "disconnected", (GCallback) 
storage_manager_disconnected_cb, application);
-               almanah_storage_manager_disconnect (priv->storage_manager, NULL);
+               g_idle_add ((GSourceFunc) storage_disconnect_idle_cb, priv->storage_manager);
        }
 
        GTK_APPLICATION_CLASS (almanah_application_parent_class)->window_removed (application, window);
diff --git a/src/export-operation.c b/src/export-operation.c
index 96e9be2..f32293e 100644
--- a/src/export-operation.c
+++ b/src/export-operation.c
@@ -301,7 +301,7 @@ export_database (AlmanahExportOperation *self, GFile *destination, AlmanahExport
        /* We ignore the progress callbacks, since this is a fairly fast operation, and it exports all the 
entries at once. */
 
        /* Get the input file (current unencrypted database) */
-       source = g_file_new_for_path (almanah_storage_manager_get_filename (self->priv->storage_manager, 
TRUE));
+       source = g_file_new_for_path (almanah_storage_manager_get_filename (self->priv->storage_manager));
 
        /* Copy the current database to that location */
        success = g_file_copy (source, destination, G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error);
diff --git a/src/import-operation.c b/src/import-operation.c
index 27d3156..3434b92 100644
--- a/src/import-operation.c
+++ b/src/import-operation.c
@@ -448,7 +448,7 @@ import_database (AlmanahImportOperation *self, GFile *source, AlmanahImportProgr
 
        /* Open the database */
        path = g_file_get_path (source);
-       database = almanah_storage_manager_new (path, NULL);
+       database = almanah_storage_manager_new (path);
        g_free (path);
 
        /* Connect to the database */
diff --git a/src/storage-manager.c b/src/storage-manager.c
index 7e22879..228a0c1 100644
--- a/src/storage-manager.c
+++ b/src/storage-manager.c
@@ -28,32 +28,24 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <string.h>
-#ifdef ENABLE_ENCRYPTION
-#include <gpgme.h>
-#endif /* ENABLE_ENCRYPTION */
 
 #include "entry.h"
 #include "storage-manager.h"
 #include "almanah-marshal.h"
 #include "vfs.h"
 
-#define ENCRYPTED_SUFFIX ".encrypted"
-
 static void almanah_storage_manager_finalize (GObject *object);
 static void almanah_storage_manager_get_property (GObject *object, guint property_id, GValue *value, 
GParamSpec *pspec);
 static void almanah_storage_manager_set_property (GObject *object, guint property_id, const GValue *value, 
GParamSpec *pspec);
 static gboolean simple_query (AlmanahStorageManager *self, const gchar *query, GError **error, ...);
 
 struct _AlmanahStorageManagerPrivate {
-       gchar *filename, *plain_filename;
-       gchar *encryption_key;
+       gchar *filename;
        sqlite3 *connection;
-       gboolean decrypted;
 };
 
 enum {
        PROP_FILENAME = 1,
-       PROP_ENCRYPTION_KEY,
 };
 
 enum {
@@ -94,12 +86,6 @@ almanah_storage_manager_class_init (AlmanahStorageManagerClass *klass)
                                                              NULL,
                                                              G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS));
 
-       g_object_class_install_property (gobject_class, PROP_ENCRYPTION_KEY,
-                                        g_param_spec_string ("encryption-key",
-                                                             "Encryption key", "The identifier for the 
encryption key in the user's keyring.",
-                                                             NULL,
-                                                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
        storage_manager_signals[SIGNAL_DISCONNECTED] = g_signal_new ("disconnected",
                                                                     G_TYPE_FROM_CLASS (klass),
                                                                     G_SIGNAL_RUN_LAST,
@@ -143,39 +129,26 @@ almanah_storage_manager_init (AlmanahStorageManager *self)
 {
        self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ALMANAH_TYPE_STORAGE_MANAGER, 
AlmanahStorageManagerPrivate);
        self->priv->filename = NULL;
-       self->priv->plain_filename = NULL;
-       self->priv->encryption_key = NULL;
-       self->priv->decrypted = FALSE;
 }
 
 /**
  * almanah_storage_manager_new:
  * @filename: database filename to open
- * @encryption_key: identifier for the encryption key to use in the user's keyring, or %NULL
  *
  * Creates a new #AlmanahStorageManager, connected to the given database @filename.
  *
- * If @filename is for an encrypted database, it will automatically be changed to the canonical filename for 
the unencrypted database, even if that
- * file doesn't exist, and even if Almanah was compiled without encryption support. Database filenames are 
always passed as the unencrypted filename.
- *
  * If @encryption_key is %NULL, encryption will be disabled.
  *
  * Return value: the new #AlmanahStorageManager
  **/
 AlmanahStorageManager *
-almanah_storage_manager_new (const gchar *filename, const gchar *encryption_key)
+almanah_storage_manager_new (const gchar *filename)
 {
-       gchar *new_filename = NULL;
        AlmanahStorageManager *sm;
 
-       if (g_str_has_suffix (filename, ENCRYPTED_SUFFIX) == TRUE)
-               filename = new_filename = g_strndup (filename, strlen (filename) - strlen (ENCRYPTED_SUFFIX));
-
        sm = g_object_new (ALMANAH_TYPE_STORAGE_MANAGER,
                           "filename", filename,
-                          "encryption-key", encryption_key,
                           NULL);
-       g_free (new_filename);
 
        return sm;
 }
@@ -186,8 +159,6 @@ almanah_storage_manager_finalize (GObject *object)
        AlmanahStorageManagerPrivate *priv = ALMANAH_STORAGE_MANAGER (object)->priv;
 
        g_free (priv->filename);
-       g_free (priv->plain_filename);
-       g_free (priv->encryption_key);
 
        /* Chain up to the parent class */
        G_OBJECT_CLASS (almanah_storage_manager_parent_class)->finalize (object);
@@ -202,9 +173,6 @@ almanah_storage_manager_get_property (GObject *object, guint property_id, GValue
                case PROP_FILENAME:
                        g_value_set_string (value, g_strdup (priv->filename));
                        break;
-               case PROP_ENCRYPTION_KEY:
-                       g_value_set_string (value, priv->encryption_key);
-                       break;
                default:
                        /* We don't have any other property... */
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -219,13 +187,9 @@ almanah_storage_manager_set_property (GObject *object, guint property_id, const
 
        switch (property_id) {
                case PROP_FILENAME:
-                       priv->plain_filename = g_strdup (g_value_get_string (value));
-                       priv->filename = g_strjoin (NULL, priv->plain_filename, ENCRYPTED_SUFFIX, NULL);
-                       break;
-               case PROP_ENCRYPTION_KEY:
-                       g_free (priv->encryption_key);
-                       priv->encryption_key = g_value_dup_string (value);
-                       g_object_notify (object, "encryption-key");
+                       if (priv->filename)
+                               g_free (priv->filename);
+                       priv->filename = g_strdup (g_value_get_string (value));
                        break;
                default:
                        /* We don't have any other property... */
@@ -256,381 +220,20 @@ create_tables (AlmanahStorageManager *self)
                simple_query (self, queries[i++], NULL);
 }
 
-#ifdef ENABLE_ENCRYPTION
-typedef struct {
-       AlmanahStorageManager *storage_manager;
-       GIOChannel *cipher_io_channel;
-       GIOChannel *plain_io_channel;
-       gpgme_data_t gpgme_cipher;
-       gpgme_data_t gpgme_plain;
-       gpgme_ctx_t context;
-} CipherOperation;
-
-static gboolean
-prepare_gpgme (AlmanahStorageManager *self, gboolean encrypting, CipherOperation *operation, GError **error)
-{
-       gpgme_error_t error_gpgme;
-
-       /* Check for a minimum GPGME version (bgo#599598) */
-       if (gpgme_check_version (MIN_GPGME_VERSION) == NULL) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_BAD_VERSION,
-                            _("GPGME is not at least version %s"),
-                            MIN_GPGME_VERSION);
-               return FALSE;
-       }
-
-       /* Check OpenPGP's supported */
-       error_gpgme = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP);
-       if (error_gpgme != GPG_ERR_NO_ERROR) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_UNSUPPORTED,
-                            _("GPGME doesn't support OpenPGP: %s"),
-                            gpgme_strerror (error_gpgme));
-               return FALSE;
-       }
-
-       /* Set up for the operation */
-       error_gpgme = gpgme_new (&(operation->context));
-       if (error_gpgme != GPG_ERR_NO_ERROR) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, 
ALMANAH_STORAGE_MANAGER_ERROR_CREATING_CONTEXT,
-                            _("Error creating cipher context: %s"),
-                            gpgme_strerror (error_gpgme));
-               return FALSE;
-       }
-
-       gpgme_set_protocol (operation->context, GPGME_PROTOCOL_OpenPGP);
-       gpgme_set_armor (operation->context, TRUE);
-       gpgme_set_textmode (operation->context, FALSE);
-
-       return TRUE;
-}
-
-static gboolean
-open_db_files (AlmanahStorageManager *self, gboolean encrypting, CipherOperation *operation, GError **error)
-{
-       GError *io_error = NULL;
-       gpgme_error_t error_gpgme;
-
-       /* Open the encrypted file */
-       operation->cipher_io_channel = g_io_channel_new_file (self->priv->filename, encrypting ? "w" : "r", 
&io_error);
-       if (operation->cipher_io_channel == NULL) {
-               g_propagate_error (error, io_error);
-               return FALSE;
-       }
-
-       /* Pass it to GPGME */
-       error_gpgme = gpgme_data_new_from_fd (&(operation->gpgme_cipher), g_io_channel_unix_get_fd 
(operation->cipher_io_channel));
-       if (error_gpgme != GPG_ERR_NO_ERROR) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_OPENING_FILE,
-                            _("Error opening encrypted database file \"%s\": %s"),
-                            self->priv->filename, gpgme_strerror (error_gpgme));
-               return FALSE;
-       }
-
-       /* Open/Create the plain file */
-       operation->plain_io_channel = g_io_channel_new_file (self->priv->plain_filename, encrypting ? "r" : 
"w", &io_error);
-       if (operation->plain_io_channel == NULL) {
-               g_propagate_error (error, io_error);
-               return FALSE;
-       }
-
-       /* Ensure the permissions are restricted to only the current user */
-       fchmod (g_io_channel_unix_get_fd (operation->plain_io_channel), S_IRWXU);
-
-       /* Pass it to GPGME */
-       error_gpgme = gpgme_data_new_from_fd (&(operation->gpgme_plain), g_io_channel_unix_get_fd 
(operation->plain_io_channel));
-       if (error_gpgme != GPG_ERR_NO_ERROR) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_OPENING_FILE,
-                            _("Error opening plain database file \"%s\": %s"),
-                            self->priv->plain_filename, gpgme_strerror (error_gpgme));
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static void
-cipher_operation_free (CipherOperation *operation)
-{
-       gpgme_data_release (operation->gpgme_cipher);
-       gpgme_data_release (operation->gpgme_plain);
-
-       if (operation->cipher_io_channel != NULL) {
-               g_io_channel_flush (operation->cipher_io_channel, NULL);
-               g_io_channel_unref (operation->cipher_io_channel);
-       }
-
-       if (operation->plain_io_channel != NULL) {
-               g_io_channel_shutdown (operation->plain_io_channel, TRUE, NULL);
-               g_io_channel_unref (operation->plain_io_channel);
-       }
-
-       /* We could free the operation before the context is even created (bgo#599598) */
-       if (operation->context != NULL) {
-               gpgme_signers_clear (operation->context);
-               gpgme_release (operation->context);
-       }
-
-       g_object_unref (operation->storage_manager);
-       g_free (operation);
-}
-
-static gboolean
-database_idle_cb (CipherOperation *operation)
-{
-       AlmanahStorageManager *self = operation->storage_manager;
-       gpgme_error_t error_gpgme;
-
-       if (gpgme_wait (operation->context, &error_gpgme, FALSE) != NULL || error_gpgme != GPG_ERR_NO_ERROR) {
-               struct stat db_stat;
-               gchar *warning_message = NULL;
-
-               /* Check to see if the encrypted file is 0B in size, which isn't good. Not much we can do 
about it except quit without deleting the
-                * plaintext database. */
-               g_stat (self->priv->filename, &db_stat);
-               if (g_file_test (self->priv->filename, G_FILE_TEST_IS_REGULAR) == FALSE || db_stat.st_size == 
0) {
-                       warning_message = g_strdup (_("The encrypted database is empty. The plain database 
file has been left undeleted as backup."));
-               } else if (g_unlink (self->priv->plain_filename) != 0) {
-                       /* Delete the plain file */
-                       warning_message = g_strdup_printf (_("Could not delete plain database file \"%s\"."), 
self->priv->plain_filename);
-               }
-
-               /* A slight assumption that we're disconnecting at this point (we're technically only 
encrypting), but a valid one. */
-               g_signal_emit (self, storage_manager_signals[SIGNAL_DISCONNECTED], 0,
-                              (error_gpgme == GPG_ERR_NO_ERROR) ? NULL: gpgme_strerror (error_gpgme),
-                              warning_message);
-               g_free (warning_message);
-
-               /* Finished! */
-               cipher_operation_free (operation);
-
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static gboolean
-decrypt_database (AlmanahStorageManager *self, GError **error)
-{
-       GError *preparation_error = NULL;
-       CipherOperation *operation;
-       gpgme_error_t error_gpgme;
-
-       operation = g_new0 (CipherOperation, 1);
-       operation->storage_manager = g_object_ref (self);
-
-       /* Set up */
-       if (prepare_gpgme (self, FALSE, operation, &preparation_error) != TRUE ||
-           open_db_files (self, FALSE, operation, &preparation_error) != TRUE) {
-               cipher_operation_free (operation);
-               g_propagate_error (error, preparation_error);
-               return FALSE;
-       }
-
-       /* Decrypt and verify! */
-       error_gpgme = gpgme_op_decrypt_verify (operation->context, operation->gpgme_cipher, 
operation->gpgme_plain);
-       if (error_gpgme != GPG_ERR_NO_ERROR) {
-               cipher_operation_free (operation);
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_DECRYPTING,
-                            _("Error decrypting database: %s"),
-                            gpgme_strerror (error_gpgme));
-               return FALSE;
-       }
-
-       /* Do this one synchronously */
-       cipher_operation_free (operation);
-
-       return TRUE;
-}
-
-static gboolean
-encrypt_database (AlmanahStorageManager *self, const gchar *encryption_key, GError **error)
-{
-       GError *preparation_error = NULL;
-       CipherOperation *operation;
-       gpgme_error_t error_gpgme;
-       gpgme_key_t gpgme_keys[2] = { NULL, };
-
-       operation = g_new0 (CipherOperation, 1);
-       operation->storage_manager = g_object_ref (self);
-
-       /* Set up */
-       if (prepare_gpgme (self, TRUE, operation, &preparation_error) != TRUE) {
-               cipher_operation_free (operation);
-               g_propagate_error (error, preparation_error);
-               return FALSE;
-       }
-
-       /* Set up signing and the recipient */
-       error_gpgme = gpgme_get_key (operation->context, encryption_key, &gpgme_keys[0], FALSE);
-       if (error_gpgme != GPG_ERR_NO_ERROR || gpgme_keys[0] == NULL) {
-               cipher_operation_free (operation);
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_GETTING_KEY,
-                            _("Error getting encryption key: %s"),
-                            gpgme_strerror (error_gpgme));
-               return FALSE;
-       }
-
-       gpgme_signers_add (operation->context, gpgme_keys[0]);
-
-       if (open_db_files (self, TRUE, operation, &preparation_error) != TRUE) {
-               cipher_operation_free (operation);
-               g_propagate_error (error, preparation_error);
-               return FALSE;
-       }
-
-       /* Encrypt and sign! */
-       error_gpgme = gpgme_op_encrypt_sign_start (operation->context, gpgme_keys, 0, operation->gpgme_plain, 
operation->gpgme_cipher);
-       gpgme_key_unref (gpgme_keys[0]);
-
-       if (error_gpgme != GPG_ERR_NO_ERROR) {
-               cipher_operation_free (operation);
-
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_ENCRYPTING,
-                            _("Error encrypting database: %s"),
-                            gpgme_strerror (error_gpgme));
-               return FALSE;
-       }
-
-       /* The operation will be completed in the idle function */
-       g_idle_add ((GSourceFunc) database_idle_cb, operation);
-
-       return TRUE;
-}
-
-static gchar *
-get_encryption_key (AlmanahStorageManager *self)
-{
-       gchar **key_parts;
-       guint i;
-       gchar *encryption_key;
-
-       encryption_key = g_strdup (self->priv->encryption_key);
-       if (encryption_key == NULL || encryption_key[0] == '\0') {
-               g_free (encryption_key);
-               return NULL;
-       }
-
-       /* Key is generally in the form openpgp:FOOBARKEY, and GPGME doesn't like the openpgp: prefix, so it 
must be removed. */
-       key_parts = g_strsplit (encryption_key, ":", 2);
-       g_free (encryption_key);
-
-       for (i = 0; key_parts[i] != NULL; i++) {
-               if (strcmp (key_parts[i], "openpgp") != 0)
-                       encryption_key = key_parts[i];
-               else
-                       g_free (key_parts[i]);
-       }
-       g_free (key_parts);
-
-       return encryption_key;
-}
-#endif /* ENABLE_ENCRYPTION */
-
-static gboolean
-back_up_file (const gchar *filename, GError **error)
-{
-       GFile *original_file, *backup_file;
-       gchar *backup_filename;
-       gboolean retval = TRUE;
-
-       /* Make a backup of the encrypted database file */
-       original_file = g_file_new_for_path (filename);
-       backup_filename = g_strdup_printf ("%s~", filename);
-       backup_file = g_file_new_for_path (backup_filename);
-       g_free (backup_filename);
-
-       if (g_file_copy (original_file, backup_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, error) == 
FALSE) {
-               retval = FALSE;
-       }
-
-       /* Ensure the backup is only readable to the current user. */
-       if (g_chmod (backup_filename, 0600) != 0 && errno != ENOENT) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, 
ALMANAH_STORAGE_MANAGER_ERROR_CREATING_CONTEXT,
-                            _("Error changing database backup file permissions: %s"),
-                            g_strerror (errno));
-               retval = FALSE;
-       }
-
-       g_object_unref (original_file);
-       g_object_unref (backup_file);
-
-       return retval;
-}
-
 gboolean
 almanah_storage_manager_connect (AlmanahStorageManager *self, GError **error)
 {
-#ifdef ENABLE_ENCRYPTION
-       struct stat encrypted_db_stat, plaintext_db_stat;
-       GError *child_error = NULL;
-
-       g_stat (self->priv->filename, &encrypted_db_stat);
-
-       if (g_chmod (self->priv->filename, 0600) != 0 && errno != ENOENT) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, 
ALMANAH_STORAGE_MANAGER_ERROR_CREATING_CONTEXT,
-                            _("Error changing database file permissions: %s"),
-                            g_strerror (errno));
-               return FALSE;
-       }
-
-       /* If we're decrypting, don't bother if the cipher file doesn't exist (i.e. the database hasn't yet 
been created), or is empty
-        * (i.e. corrupt). */
-       if (g_file_test (self->priv->filename, G_FILE_TEST_IS_REGULAR) == TRUE && encrypted_db_stat.st_size > 
0) {
-               /* Make a backup of the encrypted database file */
-               back_up_file (self->priv->filename, &child_error);
-               if (child_error != NULL) {
-                       /* Translators: the first parameter is a filename, the second is an error message. */
-                       g_warning (_("Error backing up file ‘%s’: %s"), self->priv->filename, 
child_error->message);
-                       g_clear_error (&child_error);
-               }
-
-               g_stat (self->priv->plain_filename, &plaintext_db_stat);
-
-               /* Only decrypt the database if the plaintext database doesn't exist or is empty. If the 
plaintext database exists and is non-empty,
-                * don't decrypt — just use that database. */
-               if (g_file_test (self->priv->plain_filename, G_FILE_TEST_IS_REGULAR) != TRUE || 
plaintext_db_stat.st_size == 0) {
-                       /* Decrypt the database, or display an error if that fails (but not if it fails due 
to a missing encrypted DB file — just
-                        * fall through and try to open the plain DB file in that case). */
-                       if (decrypt_database (self, &child_error) != TRUE) {
-                               if (child_error->code != G_FILE_ERROR_NOENT) {
-                                       g_propagate_error (error, child_error);
-                                       return FALSE;
-                               }
-
-                               g_error_free (child_error);
-                       }
-               }
-       }
-
-       self->priv->decrypted = TRUE;
-#else
-       /* Make a backup of the plaintext database file */
-       back_up_file (self->priv->plain_filename, &child_error);
-       if (child_error != NULL) {
-               /* Translators: the first parameter is a filename, the second is an error message. */
-               g_warning (_("Error backing up file ‘%s’: %s"), self->priv->plain_filename, 
child_error->message);
-               g_clear_error (&child_error);
-       }
-       self->priv->decrypted = FALSE;
-#endif /* ENABLE_ENCRYPTION */
-
+       /* Our beautiful SQLite VFS */
        almanah_vfs_init();
+
        /* Open the plain database */
-       if (sqlite3_open_v2 (self->priv->plain_filename, &(self->priv->connection), SQLITE_OPEN_READWRITE | 
SQLITE_OPEN_CREATE, "almanah") != SQLITE_OK) {
+       if (sqlite3_open_v2 (self->priv->filename, &(self->priv->connection), SQLITE_OPEN_READWRITE | 
SQLITE_OPEN_CREATE, "almanah") != SQLITE_OK) {
                g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, ALMANAH_STORAGE_MANAGER_ERROR_OPENING_FILE,
                             _("Could not open database \"%s\". SQLite provided the following error message: 
%s"),
                             self->priv->filename, sqlite3_errmsg (self->priv->connection));
                return FALSE;
        }
 
-       if (g_chmod (self->priv->plain_filename, 0600) != 0 && errno != ENOENT) {
-               g_set_error (error, ALMANAH_STORAGE_MANAGER_ERROR, 
ALMANAH_STORAGE_MANAGER_ERROR_CREATING_CONTEXT,
-                            _("Error changing database file permissions: %s"),
-                            g_strerror (errno));
-               return FALSE;
-       }
-
        /* Can't hurt to create the tables now */
        create_tables (self);
 
@@ -638,54 +241,19 @@ almanah_storage_manager_connect (AlmanahStorageManager *self, GError **error)
 }
 
 gboolean
-almanah_storage_manager_disconnect (AlmanahStorageManager *self, GError **error)
+almanah_storage_manager_disconnect (AlmanahStorageManager *self, __attribute__ ((unused)) GError **error)
 {
-#ifdef ENABLE_ENCRYPTION
-       gchar *encryption_key;
-       GError *child_error = NULL;
-#endif /* ENABLE_ENCRYPTION */
-
-       /* Close the DB connection */
-       sqlite3_close (self->priv->connection);
-
-#ifdef ENABLE_ENCRYPTION
-       /* If the database wasn't encrypted before we opened it, we won't encrypt it when closing. In fact, 
we'll go so far as to delete the old
-        * encrypted database file. */
-       if (self->priv->decrypted == FALSE)
-               goto delete_encrypted_db;
-
-       /* Get the encryption key */
-       encryption_key = get_encryption_key (self);
-       if (encryption_key == NULL)
-               goto delete_encrypted_db;
-
-       /* Encrypt the plain DB file */
-       if (encrypt_database (self, encryption_key, &child_error) != TRUE) {
-               g_signal_emit (self, storage_manager_signals[SIGNAL_DISCONNECTED], 0, NULL, 
child_error->message);
-
-               if (g_error_matches (child_error, ALMANAH_STORAGE_MANAGER_ERROR, 
ALMANAH_STORAGE_MANAGER_ERROR_GETTING_KEY) == TRUE)
-                       g_propagate_error (error, child_error);
-               else
-                       g_error_free (child_error);
+       int sqlite_ret;
 
-               g_free (encryption_key);
-               return FALSE;
-       }
+       sqlite_ret = sqlite3_close (self->priv->connection);
 
-       g_free (encryption_key);
-#else /* ENABLE_ENCRYPTION */
-       g_signal_emit (self, storage_manager_signals[SIGNAL_DISCONNECTED], 0, NULL, NULL);
-#endif /* !ENABLE_ENCRYPTION */
+       if (sqlite_ret != SQLITE_OK)
+               g_signal_emit (self, storage_manager_signals[SIGNAL_DISCONNECTED], 0, NULL, "Something goes 
wrong closing the database");
+       else
+               g_signal_emit (self, storage_manager_signals[SIGNAL_DISCONNECTED], 0, NULL, NULL);
 
-       return TRUE;
 
-#ifdef ENABLE_ENCRYPTION
-delete_encrypted_db:
-       /* Delete the old encrypted database and return */
-       g_unlink (self->priv->filename);
-       g_signal_emit (self, storage_manager_signals[SIGNAL_DISCONNECTED], 0, NULL, NULL);
        return TRUE;
-#endif /* ENABLE_ENCRYPTION */
 }
 
 static gboolean
@@ -1355,9 +923,9 @@ almanah_storage_manager_get_month_important_days (AlmanahStorageManager *self, G
 }
 
 const gchar *
-almanah_storage_manager_get_filename (AlmanahStorageManager *self, gboolean plain)
+almanah_storage_manager_get_filename (AlmanahStorageManager *self)
 {
-       return (plain == TRUE) ? self->priv->plain_filename : self->priv->filename;
+       return self->priv->filename;
 }
 
 /**
diff --git a/src/storage-manager.h b/src/storage-manager.h
index 51aad3d..a40a919 100644
--- a/src/storage-manager.h
+++ b/src/storage-manager.h
@@ -68,7 +68,7 @@ typedef void (*AlmanahStorageManagerSearchCallback) (AlmanahStorageManager *stor
 
 GType almanah_storage_manager_get_type (void);
 GQuark almanah_storage_manager_error_quark (void);
-AlmanahStorageManager *almanah_storage_manager_new (const gchar *filename, const gchar *encryption_key) 
G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+AlmanahStorageManager *almanah_storage_manager_new (const gchar *filename) G_GNUC_WARN_UNUSED_RESULT 
G_GNUC_MALLOC;
 
 gboolean almanah_storage_manager_connect (AlmanahStorageManager *self, GError **error);
 gboolean almanah_storage_manager_disconnect (AlmanahStorageManager *self, GError **error);
@@ -93,7 +93,7 @@ AlmanahEntry *almanah_storage_manager_get_entries (AlmanahStorageManager *self,
 gboolean *almanah_storage_manager_get_month_marked_days (AlmanahStorageManager *self, GDateYear year, 
GDateMonth month, guint *num_days);
 gboolean *almanah_storage_manager_get_month_important_days (AlmanahStorageManager *self, GDateYear year, 
GDateMonth month, guint *num_days);
 
-const gchar *almanah_storage_manager_get_filename (AlmanahStorageManager *self, gboolean plain);
+const gchar *almanah_storage_manager_get_filename (AlmanahStorageManager *self);
 
 gboolean almanah_storage_manager_entry_add_tag (AlmanahStorageManager *self, AlmanahEntry *entry, const 
gchar *tag);
 gboolean almanah_storage_manager_entry_remove_tag (AlmanahStorageManager *self, AlmanahEntry *entry, const 
gchar *tag);
diff --git a/src/vfs.c b/src/vfs.c
index 7009d75..4c52e65 100644
--- a/src/vfs.c
+++ b/src/vfs.c
@@ -36,9 +36,17 @@
 #include <errno.h>
 #include <fcntl.h>
 
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
 #include <config.h>
 
+#ifdef ENABLE_ENCRYPTION
+#include <gpgme.h>
 #define ENCRYPTED_SUFFIX ".encrypted"
+#endif /* ENABLE_ENCRYPTION */
 
 /*
 ** Size of the write buffer used by journal files in bytes.
@@ -56,208 +64,530 @@
 ** When using this VFS, the sqlite3_file* handles that SQLite uses are
 ** actually pointers to instances of type DemoFile.
 */
-typedef struct DemoFile DemoFile;
-struct DemoFile {
-  sqlite3_file base;              /* Base class. Must be first. */
-  int fd;                         /* File descriptor */
-
-  char *aBuffer;                  /* Pointer to malloc'd buffer */
-  int nBuffer;                    /* Valid bytes of data in zBuffer */
-  sqlite3_int64 iBufferOfst;      /* Offset in file of zBuffer[0] */
+typedef struct AlmanahSQLiteVFS AlmanahSQLiteVFS;
+struct AlmanahSQLiteVFS
+{
+       sqlite3_file base;              /* Base class. Must be first. */
+       int fd;                         /* File descriptor */
+
+       char *aBuffer;                  /* Pointer to malloc'd buffer */
+       int nBuffer;                    /* Valid bytes of data in zBuffer */
+       sqlite3_int64 iBufferOfst;      /* Offset in file of zBuffer[0] */
+
+       gchar *plain_filename;
+#ifdef ENABLE_ENCRYPTION
+       gchar *encrypted_filename;
+       gboolean decrypted;
+#endif /* ENABLE_ENCRYPTION */
 };
 
+#ifdef ENABLE_ENCRYPTION
+
+typedef struct {
+       GIOChannel *cipher_io_channel;
+       GIOChannel *plain_io_channel;
+       gpgme_data_t gpgme_cipher;
+       gpgme_data_t gpgme_plain;
+       gpgme_ctx_t context;
+       AlmanahSQLiteVFS *vfs;
+} CipherOperation;
+
+static gboolean
+prepare_gpgme (CipherOperation *operation)
+{
+       gpgme_error_t error_gpgme;
+
+       /* Check for a minimum GPGME version (bgo#599598) */
+       if (gpgme_check_version (MIN_GPGME_VERSION) == NULL) {
+               g_critical (_("GPGME is not at least version %s"), MIN_GPGME_VERSION);
+               return FALSE;
+       }
+
+       /* Check OpenPGP's supported */
+       error_gpgme = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP);
+       if (error_gpgme != GPG_ERR_NO_ERROR) {
+               g_critical (_("GPGME doesn't support OpenPGP: %s"), gpgme_strerror (error_gpgme));
+               return FALSE;
+       }
+
+       /* Set up for the operation */
+       error_gpgme = gpgme_new (&(operation->context));
+       if (error_gpgme != GPG_ERR_NO_ERROR) {
+               g_critical (_("Error creating cipher context: %s"), gpgme_strerror (error_gpgme));
+               return FALSE;
+       }
+
+       gpgme_set_protocol (operation->context, GPGME_PROTOCOL_OpenPGP);
+       gpgme_set_armor (operation->context, TRUE);
+       gpgme_set_textmode (operation->context, FALSE);
+
+       return TRUE;
+}
+
+static gboolean
+open_db_files (AlmanahSQLiteVFS *self, gboolean encrypting, CipherOperation *operation, GError **error)
+{
+       GError *io_error = NULL;
+       gpgme_error_t error_gpgme;
+
+       /* Open the encrypted file */
+       operation->cipher_io_channel = g_io_channel_new_file (self->encrypted_filename, encrypting ? "w" : 
"r", &io_error);
+       if (operation->cipher_io_channel == NULL) {
+               g_critical (_("Can't create a new GIOChannel for the encrypted database: %s"), 
io_error->message);
+               g_propagate_error (error, io_error);
+               return FALSE;
+       }
+
+       /* Pass it to GPGME */
+       error_gpgme = gpgme_data_new_from_fd (&(operation->gpgme_cipher), g_io_channel_unix_get_fd 
(operation->cipher_io_channel));
+       if (error_gpgme != GPG_ERR_NO_ERROR) {
+               g_critical (_("Error opening encrypted database file \"%s\": %s"), self->encrypted_filename, 
gpgme_strerror (error_gpgme));
+               return FALSE;
+       }
+
+       /* Open/Create the plain file */
+       operation->plain_io_channel = g_io_channel_new_file (self->plain_filename, encrypting ? "r" : "w", 
&io_error);
+       if (operation->plain_io_channel == NULL) {
+               g_critical (_("Can't create a new GIOChannel for the plain database: %s"), io_error->message);
+               g_propagate_error (error, io_error);
+               return FALSE;
+       }
+
+       /* Ensure the permissions are restricted to only the current user */
+       fchmod (g_io_channel_unix_get_fd (operation->plain_io_channel), S_IRWXU);
+
+       /* Pass it to GPGME */
+       error_gpgme = gpgme_data_new_from_fd (&(operation->gpgme_plain), g_io_channel_unix_get_fd 
(operation->plain_io_channel));
+       if (error_gpgme != GPG_ERR_NO_ERROR) {
+               g_critical (_("Error opening plain database file \"%s\": %s"), self->plain_filename, 
gpgme_strerror (error_gpgme));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void
+cipher_operation_free (CipherOperation *operation)
+{
+       gpgme_data_release (operation->gpgme_cipher);
+       gpgme_data_release (operation->gpgme_plain);
+
+       if (operation->cipher_io_channel != NULL) {
+               g_io_channel_flush (operation->cipher_io_channel, NULL);
+               g_io_channel_unref (operation->cipher_io_channel);
+       }
+
+       if (operation->plain_io_channel != NULL) {
+               g_io_channel_shutdown (operation->plain_io_channel, TRUE, NULL);
+               g_io_channel_unref (operation->plain_io_channel);
+       }
+
+       /* We could free the operation before the context is even created (bgo#599598) */
+       if (operation->context != NULL) {
+               gpgme_signers_clear (operation->context);
+               gpgme_release (operation->context);
+       }
+
+       g_free (operation);
+}
+
+static gboolean
+decrypt_database (AlmanahSQLiteVFS *self, GError **error)
+{
+       GError *preparation_error = NULL;
+       CipherOperation *operation;
+       gpgme_error_t error_gpgme;
+
+       operation = g_new0 (CipherOperation, 1);
+
+       /* Set up */
+       if (prepare_gpgme (operation) != TRUE || open_db_files (self, FALSE, operation, &preparation_error) 
!= TRUE) {
+               cipher_operation_free (operation);
+               g_propagate_error (error, preparation_error);
+               return FALSE;
+       }
+
+       /* Decrypt and verify! */
+       error_gpgme = gpgme_op_decrypt_verify (operation->context, operation->gpgme_cipher, 
operation->gpgme_plain);
+       if (error_gpgme != GPG_ERR_NO_ERROR) {
+               cipher_operation_free (operation);
+               g_critical (_("Error decrypting database: %s"), gpgme_strerror (error_gpgme));
+               return FALSE;
+       }
+
+       /* Do this one synchronously */
+       cipher_operation_free (operation);
+
+       return TRUE;
+}
+
+static gboolean
+encrypt_database (AlmanahSQLiteVFS *self,  const gchar *encryption_key, GError **error)
+{
+       GError *preparation_error = NULL;
+       CipherOperation *operation;
+       gpgme_error_t error_gpgme;
+       gpgme_key_t gpgme_keys[2] = { NULL, };
+
+       operation = g_new0 (CipherOperation, 1);
+       operation->vfs = self;
+
+       /* Set up */
+       if (prepare_gpgme (operation) != TRUE) {
+               cipher_operation_free (operation);
+               g_propagate_error (error, preparation_error);
+               return FALSE;
+       }
+
+       /* Set up signing and the recipient */
+       error_gpgme = gpgme_get_key (operation->context, encryption_key, &gpgme_keys[0], FALSE);
+       if (error_gpgme != GPG_ERR_NO_ERROR || gpgme_keys[0] == NULL) {
+               cipher_operation_free (operation);
+               g_critical (_("Error getting encryption key: %s"), gpgme_strerror (error_gpgme));
+               return FALSE;
+       }
+
+       gpgme_signers_add (operation->context, gpgme_keys[0]);
+
+       if (open_db_files (self, TRUE, operation, &preparation_error) != TRUE) {
+               cipher_operation_free (operation);
+               g_propagate_error (error, preparation_error);
+               return FALSE;
+       }
+
+       /* Encrypt and sign! */
+       error_gpgme = gpgme_op_encrypt_sign_start (operation->context, gpgme_keys, 0, operation->gpgme_plain, 
operation->gpgme_cipher);
+       gpgme_key_unref (gpgme_keys[0]);
+
+       if (error_gpgme != GPG_ERR_NO_ERROR) {
+               cipher_operation_free (operation);
+               g_critical (_("Error encrypting database: %s"), gpgme_strerror (error_gpgme));
+               return FALSE;
+       }
+
+       if (gpgme_wait (operation->context, &error_gpgme, TRUE) != NULL || error_gpgme != GPG_ERR_NO_ERROR) {
+               struct stat db_stat;
+               gchar *warning_message = NULL;
+
+               /* Check to see if the encrypted file is 0B in size, which isn't good. Not much we can do 
about it except quit without deleting the
+                * plaintext database. */
+               g_stat (operation->vfs->encrypted_filename, &db_stat);
+               if (g_file_test (operation->vfs->encrypted_filename, G_FILE_TEST_IS_REGULAR) == FALSE || 
db_stat.st_size == 0) {
+                       warning_message = g_strdup (_("The encrypted database is empty. The plain database 
file has been left undeleted as backup."));
+               } else if (g_unlink (operation->vfs->plain_filename) != 0) {
+                       /* Delete the plain file */
+                       warning_message = g_strdup_printf (_("Could not delete plain database file \"%s\"."), 
operation->vfs->plain_filename);
+               }
+
+               if (warning_message) {
+                       g_critical (warning_message);
+                       g_free (warning_message);
+               }
+
+               /* Finished! */
+               cipher_operation_free (operation);
+
+               return FALSE;
+       }
+
+       return TRUE;
+
+       return TRUE;
+}
+
+static gchar *
+get_encryption_key (void)
+{
+       GSettings *settings;
+       gchar *encryption_key;
+       gchar **key_parts;
+       guint i;
+
+       settings = g_settings_new ("org.gnome.almanah");
+       encryption_key = g_settings_get_string (settings, "encryption-key");
+       if (encryption_key == NULL || encryption_key[0] == '\0') {
+               g_free (encryption_key);
+               return NULL;
+       }
+
+       /* Key is generally in the form openpgp:FOOBARKEY, and GPGME doesn't like the openpgp: prefix, so it 
must be removed. */
+       key_parts = g_strsplit (encryption_key, ":", 2);
+       g_free (encryption_key);
+
+       for (i = 0; key_parts[i] != NULL; i++) {
+               if (strcmp (key_parts[i], "openpgp") != 0)
+                       encryption_key = key_parts[i];
+               else
+                       g_free (key_parts[i]);
+       }
+       g_free (key_parts);
+
+       return encryption_key;
+}
+
+#endif /* ENABLE_ENCRYPTION */
+
+static gboolean
+back_up_file (const gchar *filename)
+{
+       GError *error = NULL;
+       GFile *original_file, *backup_file;
+       gchar *backup_filename;
+       gboolean retval = TRUE;
+
+       /* Make a backup of the encrypted database file */
+       original_file = g_file_new_for_path (filename);
+       backup_filename = g_strdup_printf ("%s~", filename);
+       backup_file = g_file_new_for_path (backup_filename);
+       g_free (backup_filename);
+
+       if (g_file_copy (original_file, backup_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error) == 
FALSE) {
+               /* Translators: The first and second params are file paths, the last param is an error 
message.  */
+               g_warning (_("Error copying the file from %s to %s: %s"), original_file, backup_file, 
error->message);
+               retval = FALSE;
+       }
+
+       /* Ensure the backup is only readable to the current user. */
+       if (g_chmod (backup_filename, 0600) != 0 && errno != ENOENT) {
+               g_warning (_("Error changing database backup file permissions: %s"), g_strerror (errno));
+               retval = FALSE;
+       }
+
+       g_object_unref (original_file);
+       g_object_unref (backup_file);
+
+       return retval;
+}
+
 /*
 ** Write directly to the file passed as the first argument. Even if the
-** file has a write-buffer (DemoFile.aBuffer), ignore it.
+** file has a write-buffer (AlmanahSQLiteVFS.aBuffer), ignore it.
 */
-static int demoDirectWrite(
-  DemoFile *p,                    /* File handle */
-  const void *zBuf,               /* Buffer containing data to write */
-  int iAmt,                       /* Size of data to write in bytes */
-  sqlite_int64 iOfst              /* File offset to write to */
-){
-  off_t ofst;                     /* Return value from lseek() */
-  size_t nWrite;                  /* Return value from write() */
+static int
+demoDirectWrite (AlmanahSQLiteVFS *p,            /* File handle */
+                const void *zBuf,               /* Buffer containing data to write */
+                int iAmt,                       /* Size of data to write in bytes */
+                sqlite_int64 iOfst              /* File offset to write to */
+                )
+{
+       off_t ofst;                     /* Return value from lseek() */
+       size_t nWrite;                  /* Return value from write() */
 
-  ofst = lseek(p->fd, iOfst, SEEK_SET);
-  if( ofst!=iOfst ){
-    return SQLITE_IOERR_WRITE;
-  }
+       ofst = lseek (p->fd, iOfst, SEEK_SET);
+       if (ofst!=iOfst) {
+               return SQLITE_IOERR_WRITE;
+       }
 
-  nWrite = write(p->fd, zBuf, iAmt);
-  if( nWrite!=iAmt ){
-    return SQLITE_IOERR_WRITE;
-  }
+       nWrite = write (p->fd, zBuf, iAmt);
+       if (nWrite != iAmt){
+               return SQLITE_IOERR_WRITE;
+       }
 
-  return SQLITE_OK;
+       return SQLITE_OK;
 }
 
 /*
-** Flush the contents of the DemoFile.aBuffer buffer to disk. This is a
+** Flush the contents of the AlmanahSQLiteVFS.aBuffer buffer to disk. This is a
 ** no-op if this particular file does not have a buffer (i.e. it is not
 ** a journal file) or if the buffer is currently empty.
 */
-static int demoFlushBuffer(DemoFile *p){
-  int rc = SQLITE_OK;
-  if( p->nBuffer ){
-    rc = demoDirectWrite(p, p->aBuffer, p->nBuffer, p->iBufferOfst);
-    p->nBuffer = 0;
-  }
-  return rc;
+static int demoFlushBuffer(AlmanahSQLiteVFS *p){
+       int rc = SQLITE_OK;
+       if( p->nBuffer ){
+               rc = demoDirectWrite(p, p->aBuffer, p->nBuffer, p->iBufferOfst);
+               p->nBuffer = 0;
+       }
+       return rc;
 }
 
 /*
 ** Close a file.
 */
-static int demoClose(sqlite3_file *pFile){
-  int rc;
-  DemoFile *p = (DemoFile*)pFile;
-  rc = demoFlushBuffer(p);
-  sqlite3_free(p->aBuffer);
-  close(p->fd);
-  return rc;
+static int
+demoClose (sqlite3_file *pFile)
+{
+       int rc;
+       AlmanahSQLiteVFS *self = (AlmanahSQLiteVFS*) pFile;
+#ifdef ENABLE_ENCRYPTION
+       gchar *encryption_key;
+       GError *child_error = NULL;
+#endif /* ENABLE_ENCRYPTION */
+
+       rc = demoFlushBuffer (self);
+       sqlite3_free (self->aBuffer);
+       close (self->fd);
+
+#ifdef ENABLE_ENCRYPTION
+       /* If the database wasn't encrypted before we opened it, we won't encrypt it when closing. In fact, 
we'll go so far as to delete the old
+        * encrypted database file. */
+       if (self->decrypted == FALSE)
+               goto delete_encrypted_db;
+
+       /* Get the encryption key */
+       encryption_key = get_encryption_key ();
+       if (encryption_key == NULL)
+               goto delete_encrypted_db;
+
+       /* Encrypt the plain DB file */
+       if (encrypt_database (self, encryption_key, &child_error) != TRUE) {
+               rc = SQLITE_IOERR;
+       }
+
+       g_free (encryption_key);
+#endif /* ENABLE_ENCRYPTION */
+
+       return rc;
+
+#ifdef ENABLE_ENCRYPTION
+ delete_encrypted_db:
+       /* Delete the old encrypted database and return */
+       g_unlink (self->encrypted_filename);
+       return rc;
+#endif /* ENABLE_ENCRYPTION */
 }
 
 /*
 ** Read data from a file.
 */
-static int demoRead(
-  sqlite3_file *pFile, 
-  void *zBuf, 
-  int iAmt, 
-  sqlite_int64 iOfst
-){
-  DemoFile *p = (DemoFile*)pFile;
-  off_t ofst;                     /* Return value from lseek() */
-  int nRead;                      /* Return value from read() */
-  int rc;                         /* Return code from demoFlushBuffer() */
-
-  /* Flush any data in the write buffer to disk in case this operation
-  ** is trying to read data the file-region currently cached in the buffer.
-  ** It would be possible to detect this case and possibly save an 
-  ** unnecessary write here, but in practice SQLite will rarely read from
-  ** a journal file when there is data cached in the write-buffer.
-  */
-  rc = demoFlushBuffer(p);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  }
-
-  ofst = lseek(p->fd, iOfst, SEEK_SET);
-  if( ofst!=iOfst ){
-    return SQLITE_IOERR_READ;
-  }
-  nRead = read(p->fd, zBuf, iAmt);
-
-  if( nRead==iAmt ){
-    return SQLITE_OK;
-  }else if( nRead>=0 ){
-    return SQLITE_IOERR_SHORT_READ;
-  }
-
-  return SQLITE_IOERR_READ;
+static int
+demoRead (sqlite3_file *pFile,  void *zBuf,  int iAmt,  sqlite_int64 iOfst)
+{
+       AlmanahSQLiteVFS *p = (AlmanahSQLiteVFS*)pFile;
+       off_t ofst;                     /* Return value from lseek() */
+       int nRead;                      /* Return value from read() */
+       int rc;                         /* Return code from demoFlushBuffer() */
+
+       /* Flush any data in the write buffer to disk in case this operation
+       ** is trying to read data the file-region currently cached in the buffer.
+       ** It would be possible to detect this case and possibly save an 
+       ** unnecessary write here, but in practice SQLite will rarely read from
+       ** a journal file when there is data cached in the write-buffer.
+       */
+       rc = demoFlushBuffer (p);
+       if (rc!=SQLITE_OK) {
+               return rc;
+       }
+
+       ofst = lseek (p->fd, iOfst, SEEK_SET);
+       if (ofst!=iOfst) {
+               return SQLITE_IOERR_READ;
+       }
+       nRead = read (p->fd, zBuf, iAmt);
+
+       if (nRead==iAmt) {
+               return SQLITE_OK;
+       } else if (nRead>=0) {
+               return SQLITE_IOERR_SHORT_READ;
+       }
+
+       return SQLITE_IOERR_READ;
 }
 
 /*
 ** Write data to a crash-file.
 */
-static int demoWrite(
-  sqlite3_file *pFile, 
-  const void *zBuf, 
-  int iAmt, 
-  sqlite_int64 iOfst
-){
-  DemoFile *p = (DemoFile*)pFile;
+static int
+demoWrite (sqlite3_file *pFile,  const void *zBuf, int iAmt, sqlite_int64 iOfst)
+{
+       AlmanahSQLiteVFS *p = (AlmanahSQLiteVFS*)pFile;
   
-  if( p->aBuffer ){
-    char *z = (char *)zBuf;       /* Pointer to remaining data to write */
-    int n = iAmt;                 /* Number of bytes at z */
-    sqlite3_int64 i = iOfst;      /* File offset to write to */
-
-    while( n>0 ){
-      int nCopy;                  /* Number of bytes to copy into buffer */
-
-      /* If the buffer is full, or if this data is not being written directly
-      ** following the data already buffered, flush the buffer. Flushing
-      ** the buffer is a no-op if it is empty.  
-      */
-      if( p->nBuffer==SQLITE_DEMOVFS_BUFFERSZ || p->iBufferOfst+p->nBuffer!=i ){
-        int rc = demoFlushBuffer(p);
-        if( rc!=SQLITE_OK ){
-          return rc;
-        }
-      }
-      assert( p->nBuffer==0 || p->iBufferOfst+p->nBuffer==i );
-      p->iBufferOfst = i - p->nBuffer;
-
-      /* Copy as much data as possible into the buffer. */
-      nCopy = SQLITE_DEMOVFS_BUFFERSZ - p->nBuffer;
-      if( nCopy>n ){
-        nCopy = n;
-      }
-      memcpy(&p->aBuffer[p->nBuffer], z, nCopy);
-      p->nBuffer += nCopy;
-
-      n -= nCopy;
-      i += nCopy;
-      z += nCopy;
-    }
-  }else{
-    return demoDirectWrite(p, zBuf, iAmt, iOfst);
-  }
-
-  return SQLITE_OK;
+       if (p->aBuffer) {
+               char *z = (char *)zBuf;       /* Pointer to remaining data to write */
+               int n = iAmt;                 /* Number of bytes at z */
+               sqlite3_int64 i = iOfst;      /* File offset to write to */
+
+               while (n > 0) {
+                       int nCopy;                  /* Number of bytes to copy into buffer */
+
+                       /* If the buffer is full, or if this data is not being written directly
+                       ** following the data already buffered, flush the buffer. Flushing
+                       ** the buffer is a no-op if it is empty.  
+                       */
+                       if (p->nBuffer==SQLITE_DEMOVFS_BUFFERSZ || p->iBufferOfst+p->nBuffer!=i) {
+                               int rc = demoFlushBuffer (p);
+                               if (rc!=SQLITE_OK) {
+                                       return rc;
+                               }
+                       }
+                       assert (p->nBuffer==0 || p->iBufferOfst+p->nBuffer==i);
+                       p->iBufferOfst = i - p->nBuffer;
+
+                       /* Copy as much data as possible into the buffer. */
+                       nCopy = SQLITE_DEMOVFS_BUFFERSZ - p->nBuffer;
+                       if (nCopy>n) {
+                               nCopy = n;
+                       }
+                       memcpy (&p->aBuffer[p->nBuffer], z, nCopy);
+                       p->nBuffer += nCopy;
+
+                       n -= nCopy;
+                       i += nCopy;
+                       z += nCopy;
+               }
+       } else {
+               return demoDirectWrite (p, zBuf, iAmt, iOfst);
+       }
+
+       return SQLITE_OK;
 }
 
 /*
 ** Truncate a file. This is a no-op for this VFS (see header comments at
 ** the top of the file).
 */
-static int demoTruncate(sqlite3_file *pFile, sqlite_int64 size){
+static int
+demoTruncate(sqlite3_file *pFile, sqlite_int64 size)
+{
 #if 0
-  if( ftruncate(((DemoFile *)pFile)->fd, size) ) return SQLITE_IOERR_TRUNCATE;
+       if (ftruncate(((AlmanahSQLiteVFS *)pFile)->fd, size))
+               return SQLITE_IOERR_TRUNCATE;
 #endif
-  return SQLITE_OK;
+       return SQLITE_OK;
 }
 
 /*
 ** Sync the contents of the file to the persistent media.
 */
-static int demoSync(sqlite3_file *pFile, int flags){
-  DemoFile *p = (DemoFile*)pFile;
-  int rc;
+static int
+demoSync (sqlite3_file *pFile, int flags)
+{
+       AlmanahSQLiteVFS *p = (AlmanahSQLiteVFS*) pFile;
+       int rc;
 
-  rc = demoFlushBuffer(p);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  }
+       rc = demoFlushBuffer (p);
+       if (rc!=SQLITE_OK) {
+               return rc;
+       }
 
-  rc = fsync(p->fd);
-  return (rc==0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
+       rc = fsync (p->fd);
+       return (rc==0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
 }
 
 /*
 ** Write the size of the file in bytes to *pSize.
 */
-static int demoFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
-  DemoFile *p = (DemoFile*)pFile;
-  int rc;                         /* Return code from fstat() call */
-  struct stat sStat;              /* Output of fstat() call */
-
-  /* Flush the contents of the buffer to disk. As with the flush in the
-  ** demoRead() method, it would be possible to avoid this and save a write
-  ** here and there. But in practice this comes up so infrequently it is
-  ** not worth the trouble.
-  */
-  rc = demoFlushBuffer(p);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  }
-
-  rc = fstat(p->fd, &sStat);
-  if( rc!=0 ) return SQLITE_IOERR_FSTAT;
-  *pSize = sStat.st_size;
-  return SQLITE_OK;
+static int
+demoFileSize (sqlite3_file *pFile, sqlite_int64 *pSize)
+{
+       AlmanahSQLiteVFS *p = (AlmanahSQLiteVFS*)pFile;
+       int rc;                         /* Return code from fstat() call */
+       struct stat sStat;              /* Output of fstat() call */
+
+       /* Flush the contents of the buffer to disk. As with the flush in the
+       ** demoRead() method, it would be possible to avoid this and save a write
+       ** here and there. But in practice this comes up so infrequently it is
+       ** not worth the trouble.
+       */
+       rc = demoFlushBuffer(p);
+       if (rc != SQLITE_OK) {
+               return rc;
+       }
+
+       rc = fstat (p->fd, &sStat);
+       if (rc!=0)
+               return SQLITE_IOERR_FSTAT;
+       *pSize = sStat.st_size;
+       return SQLITE_OK;
 }
 
 /*
@@ -267,21 +597,21 @@ static int demoFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
 ** file is found in the file-system it is rolled back.
 */
 static int demoLock(sqlite3_file *pFile, int eLock){
-  return SQLITE_OK;
+       return SQLITE_OK;
 }
 static int demoUnlock(sqlite3_file *pFile, int eLock){
-  return SQLITE_OK;
+       return SQLITE_OK;
 }
 static int demoCheckReservedLock(sqlite3_file *pFile, int *pResOut){
-  *pResOut = 0;
-  return SQLITE_OK;
+       *pResOut = 0;
+       return SQLITE_OK;
 }
 
 /*
 ** No xFileControl() verbs are implemented by this VFS.
 */
 static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){
-  return SQLITE_OK;
+       return SQLITE_OK;
 }
 
 /*
@@ -290,21 +620,21 @@ static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){
 ** access to some extent. But it is also safe to simply return 0.
 */
 static int demoSectorSize(sqlite3_file *pFile){
-  return 0;
+       return 0;
 }
 static int demoDeviceCharacteristics(sqlite3_file *pFile){
-  return 0;
+       return 0;
 }
 
 /*
 ** Open a file handle.
 */
 static int
-demoOpen(sqlite3_vfs *pVfs,              /* VFS */
-        const char *zName,              /* File to open, or 0 for a temp file */
-        sqlite3_file *pFile,            /* Pointer to DemoFile struct to populate */
-        int flags,                      /* Input SQLITE_OPEN_XXX flags */
-        int *pOutFlags                  /* Output SQLITE_OPEN_XXX flags (or NULL) */
+demoOpen (__attribute__ ((unused)) sqlite3_vfs *pVfs, /* VFS */
+         const char *zName,                          /* File to open, or 0 for a temp file */
+         sqlite3_file *pFile,                        /* Pointer to AlmanahSQLiteVFS struct to populate */
+         int flags,                                  /* Input SQLITE_OPEN_XXX flags */
+         int *pOutFlags                              /* Output SQLITE_OPEN_XXX flags (or NULL) */
         )
 {
        static const sqlite3_io_methods demoio = {
@@ -323,7 +653,7 @@ demoOpen(sqlite3_vfs *pVfs,              /* VFS */
                demoDeviceCharacteristics     /* xDeviceCharacteristics */
        };
 
-       DemoFile *p = (DemoFile*) pFile; /* Populate this structure */
+       AlmanahSQLiteVFS *self = (AlmanahSQLiteVFS*) pFile; /* Populate this structure */
        int oflags = 0;                 /* flags to pass to open() call */
        char *aBuf = 0;
 
@@ -338,24 +668,89 @@ demoOpen(sqlite3_vfs *pVfs,              /* VFS */
                }
        }
 
+       memset(self, 0, sizeof(AlmanahSQLiteVFS));
+
+       self->plain_filename = g_strdup (zName);
+
+#ifdef ENABLE_ENCRYPTION
+       struct stat encrypted_db_stat, plaintext_db_stat;
+       GError *child_error = NULL;
+
+       self->encrypted_filename = g_strdup_printf ("%s%s", self->plain_filename, ENCRYPTED_SUFFIX);
+
+       if (g_chmod (self->encrypted_filename, 0600) != 0 && errno != ENOENT) {
+               return SQLITE_IOERR;
+       }
+
+       g_stat (self->encrypted_filename, &encrypted_db_stat);
+
+       /* If we're decrypting, don't bother if the cipher file doesn't exist (i.e. the database hasn't yet 
been created), or is empty
+        * (i.e. corrupt). */
+       if (g_file_test (self->encrypted_filename, G_FILE_TEST_IS_REGULAR) == TRUE && 
encrypted_db_stat.st_size > 0) {
+               /* Make a backup of the encrypted database file */
+               if (back_up_file (self->encrypted_filename) != FALSE) {
+                       /* Translators: the first parameter is a filename, the second is an error message. */
+                       g_warning (_("Error backing up file ‘%s’"), self->encrypted_filename);
+                       g_clear_error (&child_error);
+               }
+
+               g_stat (self->plain_filename, &plaintext_db_stat);
+
+               /* Only decrypt the database if the plaintext database doesn't exist or is empty. If the 
plaintext database exists and is non-empty,
+                * don't decrypt — just use that database. */
+               if (g_file_test (self->plain_filename, G_FILE_TEST_IS_REGULAR) != TRUE || 
plaintext_db_stat.st_size == 0) {
+                       /* Decrypt the database, or display an error if that fails (but not if it fails due 
to a missing encrypted DB file — just
+                        * fall through and try to open the plain DB file in that case). */
+                       if (decrypt_database (self, &child_error) != TRUE) {
+                               if (child_error->code != G_FILE_ERROR_NOENT) {
+                                       g_free (self->plain_filename);
+                                       g_free (self->encrypted_filename);
+                                       return SQLITE_IOERR;
+                               }
+
+                               g_error_free (child_error);
+                       }
+               }
+       }
+
+       self->decrypted = TRUE;
+#else
+       /* Make a backup of the plaintext database file */
+       if (back_up_file (self->plain_filename) != TRUE) {
+               /* Translators: the first parameter is a filename. */
+               g_warning (_("Error backing up file ‘%s’"), self->priv->plain_filename);
+               g_clear_error (&child_error);
+       }
+       self->decrypted = FALSE;
+#endif /* ENABLE_ENCRYPTION */
+
        if (flags & SQLITE_OPEN_EXCLUSIVE) oflags |= O_EXCL;
        if (flags & SQLITE_OPEN_CREATE)    oflags |= O_CREAT;
        if (flags & SQLITE_OPEN_READONLY)  oflags |= O_RDONLY;
        if (flags & SQLITE_OPEN_READWRITE) oflags |= O_RDWR;
 
-       memset(p, 0, sizeof(DemoFile));
-       p->fd = open (zName, oflags, 0600);
-       if (p->fd < 0) {
+       self->fd = open (self->plain_filename, oflags, 0600);
+       if (self->fd < 0) {
                sqlite3_free (aBuf);
                return SQLITE_CANTOPEN;
        }
-       p->aBuffer = aBuf;
+
+       if (g_chmod (self->plain_filename, 0600) != 0 && errno != ENOENT) {
+               g_critical (_("Error changing database file permissions: %s"), g_strerror (errno));
+               sqlite3_free (aBuf);
+               g_free (self->plain_filename);
+               g_free (self->encrypted_filename);
+               close (self->fd);
+               return SQLITE_IOERR;
+       }
+
+       self->aBuffer = aBuf;
 
        if (pOutFlags) {
                *pOutFlags = flags;
        }
 
-       p->base.pMethods = &demoio;
+       self->base.pMethods = &demoio;
 
        return SQLITE_OK;
 }
@@ -366,32 +761,32 @@ demoOpen(sqlite3_vfs *pVfs,              /* VFS */
 ** file has been synced to disk before returning.
 */
 static int demoDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
-  int rc;                         /* Return code */
-
-  rc = unlink(zPath);
-  if( rc!=0 && errno==ENOENT ) return SQLITE_OK;
-
-  if( rc==0 && dirSync ){
-    int dfd;                      /* File descriptor open on directory */
-    int i;                        /* Iterator variable */
-    char zDir[MAXPATHNAME+1];     /* Name of directory containing file zPath */
-
-    /* Figure out the directory name from the path of the file deleted. */
-    sqlite3_snprintf(MAXPATHNAME, zDir, "%s", zPath);
-    zDir[MAXPATHNAME] = '\0';
-    for(i=strlen(zDir); i>1 && zDir[i]!='/'; i++);
-    zDir[i] = '\0';
-
-    /* Open a file-descriptor on the directory. Sync. Close. */
-    dfd = open(zDir, O_RDONLY, 0);
-    if( dfd<0 ){
-      rc = -1;
-    }else{
-      rc = fsync(dfd);
-      close(dfd);
-    }
-  }
-  return (rc==0 ? SQLITE_OK : SQLITE_IOERR_DELETE);
+       int rc;                         /* Return code */
+
+       rc = unlink(zPath);
+       if( rc!=0 && errno==ENOENT ) return SQLITE_OK;
+
+       if( rc==0 && dirSync ){
+               int dfd;                      /* File descriptor open on directory */
+               int i;                        /* Iterator variable */
+               char zDir[MAXPATHNAME+1];     /* Name of directory containing file zPath */
+
+               /* Figure out the directory name from the path of the file deleted. */
+               sqlite3_snprintf(MAXPATHNAME, zDir, "%s", zPath);
+               zDir[MAXPATHNAME] = '\0';
+               for(i=strlen(zDir); i>1 && zDir[i]!='/'; i++);
+               zDir[i] = '\0';
+
+               /* Open a file-descriptor on the directory. Sync. Close. */
+               dfd = open(zDir, O_RDONLY, 0);
+               if( dfd<0 ){
+                       rc = -1;
+               }else{
+                       rc = fsync(dfd);
+                       close(dfd);
+               }
+       }
+       return (rc==0 ? SQLITE_OK : SQLITE_IOERR_DELETE);
 }
 
 #ifndef F_OK
@@ -409,25 +804,25 @@ static int demoDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
 ** is both readable and writable.
 */
 static int demoAccess(
-  sqlite3_vfs *pVfs, 
-  const char *zPath, 
-  int flags, 
-  int *pResOut
-){
-  int rc;                         /* access() return code */
-  int eAccess = F_OK;             /* Second argument to access() */
-
-  assert( flags==SQLITE_ACCESS_EXISTS       /* access(zPath, F_OK) */
-       || flags==SQLITE_ACCESS_READ         /* access(zPath, R_OK) */
-       || flags==SQLITE_ACCESS_READWRITE    /* access(zPath, R_OK|W_OK) */
-  );
-
-  if( flags==SQLITE_ACCESS_READWRITE ) eAccess = R_OK|W_OK;
-  if( flags==SQLITE_ACCESS_READ )      eAccess = R_OK;
-
-  rc = access(zPath, eAccess);
-  *pResOut = (rc==0);
-  return SQLITE_OK;
+                     sqlite3_vfs *pVfs, 
+                     const char *zPath, 
+                     int flags, 
+                     int *pResOut
+                     ){
+       int rc;                         /* access() return code */
+       int eAccess = F_OK;             /* Second argument to access() */
+
+       assert( flags==SQLITE_ACCESS_EXISTS       /* access(zPath, F_OK) */
+               || flags==SQLITE_ACCESS_READ         /* access(zPath, R_OK) */
+               || flags==SQLITE_ACCESS_READWRITE    /* access(zPath, R_OK|W_OK) */
+               );
+
+       if( flags==SQLITE_ACCESS_READWRITE ) eAccess = R_OK|W_OK;
+       if( flags==SQLITE_ACCESS_READ )      eAccess = R_OK;
+
+       rc = access(zPath, eAccess);
+       *pResOut = (rc==0);
+       return SQLITE_OK;
 }
 
 /*
@@ -442,23 +837,23 @@ static int demoAccess(
 **   2. Full paths begin with a '/' character.
 */
 static int demoFullPathname(
-  sqlite3_vfs *pVfs,              /* VFS */
-  const char *zPath,              /* Input path (possibly a relative path) */
-  int nPathOut,                   /* Size of output buffer in bytes */
-  char *zPathOut                  /* Pointer to output buffer */
-){
-  char zDir[MAXPATHNAME+1];
-  if( zPath[0]=='/' ){
-    zDir[0] = '\0';
-  }else{
-    getcwd(zDir, sizeof(zDir));
-  }
-  zDir[MAXPATHNAME] = '\0';
+                           sqlite3_vfs *pVfs,              /* VFS */
+                           const char *zPath,              /* Input path (possibly a relative path) */
+                           int nPathOut,                   /* Size of output buffer in bytes */
+                           char *zPathOut                  /* Pointer to output buffer */
+                           ){
+       char zDir[MAXPATHNAME+1];
+       if( zPath[0]=='/' ){
+               zDir[0] = '\0';
+       }else{
+               getcwd(zDir, sizeof(zDir));
+       }
+       zDir[MAXPATHNAME] = '\0';
 
-  sqlite3_snprintf(nPathOut, zPathOut, "%s/%s", zDir, zPath);
-  zPathOut[nPathOut-1] = '\0';
+       sqlite3_snprintf(nPathOut, zPathOut, "%s/%s", zDir, zPath);
+       zPathOut[nPathOut-1] = '\0';
 
-  return SQLITE_OK;
+       return SQLITE_OK;
 }
 
 /*
@@ -474,17 +869,17 @@ static int demoFullPathname(
 ** this functionality, so the following functions are no-ops.
 */
 static void *demoDlOpen(sqlite3_vfs *pVfs, const char *zPath){
-  return 0;
+       return 0;
 }
 static void demoDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
-  sqlite3_snprintf(nByte, zErrMsg, "Loadable extensions are not supported");
-  zErrMsg[nByte-1] = '\0';
+       sqlite3_snprintf(nByte, zErrMsg, "Loadable extensions are not supported");
+       zErrMsg[nByte-1] = '\0';
 }
 static void (*demoDlSym(sqlite3_vfs *pVfs, void *pH, const char *z))(void){
-  return 0;
+       return 0;
 }
 static void demoDlClose(sqlite3_vfs *pVfs, void *pHandle){
-  return;
+       return;
 }
 
 /*
@@ -492,7 +887,7 @@ static void demoDlClose(sqlite3_vfs *pVfs, void *pHandle){
 ** buffer with pseudo-random data.
 */
 static int demoRandomness(sqlite3_vfs *pVfs, int nByte, char *zByte){
-  return SQLITE_OK;
+       return SQLITE_OK;
 }
 
 /*
@@ -500,9 +895,9 @@ static int demoRandomness(sqlite3_vfs *pVfs, int nByte, char *zByte){
 ** of microseconds slept for.
 */
 static int demoSleep(sqlite3_vfs *pVfs, int nMicro){
-  sleep(nMicro / 1000000);
-  usleep(nMicro % 1000000);
-  return nMicro;
+       sleep(nMicro / 1000000);
+       usleep(nMicro % 1000000);
+       return nMicro;
 }
 
 /*
@@ -517,9 +912,9 @@ static int demoSleep(sqlite3_vfs *pVfs, int nMicro){
 ** "year 2038" problem that afflicts systems that store time this way). 
 */
 static int demoCurrentTime(sqlite3_vfs *pVfs, double *pTime){
-  time_t t = time(0);
-  *pTime = t/86400.0 + 2440587.5; 
-  return SQLITE_OK;
+       time_t t = time(0);
+       *pTime = t/86400.0 + 2440587.5; 
+       return SQLITE_OK;
 }
 
 /*
@@ -528,31 +923,34 @@ static int demoCurrentTime(sqlite3_vfs *pVfs, double *pTime){
 **
 **   sqlite3_vfs_register(sqlite3_demovfs(), 0);
 */
-sqlite3_vfs *sqlite3_demovfs(void){
-  static sqlite3_vfs demovfs = {
-    1,                            /* iVersion */
-    sizeof(DemoFile),             /* szOsFile */
-    MAXPATHNAME,                  /* mxPathname */
-    0,                            /* pNext */
-    "almanah",                    /* zName */
-    0,                            /* pAppData */
-    demoOpen,                     /* xOpen */
-    demoDelete,                   /* xDelete */
-    demoAccess,                   /* xAccess */
-    demoFullPathname,             /* xFullPathname */
-    demoDlOpen,                   /* xDlOpen */
-    demoDlError,                  /* xDlError */
-    demoDlSym,                    /* xDlSym */
-    demoDlClose,                  /* xDlClose */
-    demoRandomness,               /* xRandomness */
-    demoSleep,                    /* xSleep */
-    demoCurrentTime,              /* xCurrentTime */
-  };
-  return &demovfs;
+sqlite3_vfs*
+sqlite3_demovfs (void)
+{
+       static sqlite3_vfs demovfs = {
+               1,                            /* iVersion */
+               sizeof(AlmanahSQLiteVFS),     /* szOsFile */
+               MAXPATHNAME,                  /* mxPathname */
+               0,                            /* pNext */
+               "almanah",                    /* zName */
+               0,                            /* pAppData */
+               demoOpen,                     /* xOpen */
+               demoDelete,                   /* xDelete */
+               demoAccess,                   /* xAccess */
+               demoFullPathname,             /* xFullPathname */
+               demoDlOpen,                   /* xDlOpen */
+               demoDlError,                  /* xDlError */
+               demoDlSym,                    /* xDlSym */
+               demoDlClose,                  /* xDlClose */
+               demoRandomness,               /* xRandomness */
+               demoSleep,                    /* xSleep */
+               demoCurrentTime,              /* xCurrentTime */
+       };
+
+       return &demovfs;
 }
 
 int
-almanah_vfs_init(void)
+almanah_vfs_init (void)
 {
-       return sqlite3_vfs_register(sqlite3_demovfs(), 0);
+       return sqlite3_vfs_register (sqlite3_demovfs(), 0);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]