[libgda] Initial SQLCipher provider



commit a7ae522d95afe600eb12cae17f35bb1a1e2dfbc2
Author: Vivien Malerba <malerba gnome-db org>
Date:   Mon Sep 13 23:02:23 2010 +0200

    Initial SQLCipher provider
    
    Uses Zetetic's SQLCipher (http://www.zetetic.net/code/sqlcipher)
    version 1.1.7 to create the "SQLCipher" database provider
    with which one can access encrypted SQLite databases

 configure.ac                                       |   17 +
 doc/C/prov-notes.xml                               |   51 +
 libgda/sqlite/Makefile.am                          |   34 +-
 libgda/sqlite/gda-sqlite-blob-op.c                 |    6 +-
 libgda/sqlite/gda-sqlite-handler-bin.c             |    6 +-
 libgda/sqlite/gda-sqlite-handler-boolean.c         |    6 +-
 libgda/sqlite/gda-sqlite-provider.c                |   29 +-
 libgda/sqlite/gda-sqlite-pstmt.c                   |    6 +-
 libgda/sqlite/gda-sqlite-recordset.c               |    6 +-
 libgda/sqlite/gda-sqlite.h                         |   21 +-
 libgda/sqlite/gda-symbols-util.c                   |    4 +
 libgda/sqlite/gda-symbols-util.h                   |    3 +
 po/POTFILES.in                                     |   13 +
 po/POTFILES.skip                                   |    1 +
 providers/Makefile.am                              |    7 +-
 providers/sqlcipher/.gitignore                     |    2 +
 providers/sqlcipher/COPYING.sqlcipher              |   28 +
 providers/sqlcipher/Makefile.am                    |   57 +
 providers/sqlcipher/NOTE_for_new_SQLCipher_version |   17 +
 providers/sqlcipher/libgda-sqlcipher-4.0.pc.in     |    9 +
 providers/sqlcipher/libmain.c                      |  105 +
 providers/sqlcipher/sqlcipher.patch                | 2483 ++++++++++++++++++++
 .../sqlcipher/sqlcipher_specs_add_column.xml.in    |    1 +
 providers/sqlcipher/sqlcipher_specs_auth.xml.in    |    6 +
 .../sqlcipher/sqlcipher_specs_create_db.xml.in     |    1 +
 .../sqlcipher/sqlcipher_specs_create_index.xml.in  |    1 +
 .../sqlcipher/sqlcipher_specs_create_table.xml.in  |    1 +
 .../sqlcipher/sqlcipher_specs_create_view.xml.in   |    1 +
 providers/sqlcipher/sqlcipher_specs_drop_db.xml.in |    1 +
 .../sqlcipher/sqlcipher_specs_drop_index.xml.in    |    1 +
 .../sqlcipher/sqlcipher_specs_drop_table.xml.in    |    1 +
 .../sqlcipher/sqlcipher_specs_drop_view.xml.in     |    1 +
 providers/sqlcipher/sqlcipher_specs_dsn.xml.in     |    1 +
 .../sqlcipher/sqlcipher_specs_rename_table.xml.in  |    1 +
 34 files changed, 2886 insertions(+), 42 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 870b2e6..c0a3041 100644
--- a/configure.ac
+++ b/configure.ac
@@ -419,6 +419,20 @@ dnl *********************************
 GOBJECT_INTROSPECTION_CHECK([0.6.5])
 
 dnl ******************************
+dnl Checks for libcrypto
+dnl ******************************
+
+LIBCRYPTO_MODULES="libcrypto"
+PKG_CHECK_MODULES(LIBCRYPTO, $LIBCRYPTO_MODULES, have_crypto=yes, have_crypto=no)
+AM_CONDITIONAL(HAVE_LIBCRYPTO, test x"$have_crypto" = "xyes")
+if test x"$have_crypto" = "xyes"
+then
+        LIBCRYPTO_CFLAGS="$LIBCRYPTO_CFLAGS -DHAVE_LIBCRYPTO"
+fi
+AC_SUBST(LIBCRYPTO_CFLAGS)
+AC_SUBST(LIBCRYPTO_LIBS)
+
+dnl ******************************
 dnl Checks for libgcrypt
 dnl ******************************
 LIBGCRYPT_CFLAGS=""
@@ -1810,6 +1824,8 @@ providers/skel-implementation/capi/Makefile
 providers/skel-implementation/capi/libgda-capi-4.0.pc
 providers/skel-implementation/models/Makefile
 providers/skel-implementation/models/libgda-models-4.0.pc
+providers/sqlcipher/Makefile
+providers/sqlcipher/libgda-sqlcipher-4.0.pc
 libgda-report/Makefile
 libgda-report/engine/Makefile
 libgda-report/DocBook/Makefile
@@ -1895,6 +1911,7 @@ dnl echo "      ODBC = `if test x$odbcdir != x; then echo yes; else echo no; fi`
 echo "      Oracle = `if test x$oracledir != x; then echo yes; else echo no; fi`"
 echo "      PostgreSQL = `if test x$postgresdir != x; then echo yes; else echo no; fi`"
 echo "      SQLite = yes `if test x$have_sqlite = xyes; then echo '(from system installation)'; else echo '(embedded)'; fi`"
+echo "      SQLCipher = `if test x$have_crypto != xyes; then echo no; else echo yes; fi`"
 dnl echo "      Sybase = `if test x$sybasedir != x; then echo yes; else echo no; fi`"
 dnl echo "      xBase (dBase, Clipper, FoxPro) = `if test x$xbasedir != x; then echo yes; else echo no; fi`"
 dnl echo "      LDAP = `if test x$ldapdir != x; then echo yes; else echo no; fi`"
diff --git a/doc/C/prov-notes.xml b/doc/C/prov-notes.xml
index 41be401..2d90032 100644
--- a/doc/C/prov-notes.xml
+++ b/doc/C/prov-notes.xml
@@ -40,5 +40,56 @@
       Also refer to the <link linkend="limitations_oracle">Oracle's provider's limitations</link>.
     </para>
   </sect1>
+
+  <sect1 id="provider_notes_sqlcipher"><title>For SQLCipher</title>
+  <para>
+    The SQLCipher database provider allows one to connect to a database encrypted using the
+    <ulink url="http://www.zetetic.net/code/sqlcipher";>SQLCipher</ulink> adaptations to the SQLite
+    database. This section deals about how to manage the passphrase associated with a database file, please
+    also consult the information <ulink url="http://www.zetetic.net/code/sqlcipher";>provided by SQLCipher</ulink>
+    before attempting to use this database provider.
+  </para>
+  <para>
+    The first noticeable point is that any SQLite database file can be opened using the SQLCipher and
+    will remain useable with the "standard" SQLite provider as long as it's not explicitely encrypted using
+    a passphrase.
+  </para>
+  <sect2>
+    <title>How to create and encrypted database</title>
+    <para>
+      To create an encrypted database, you can use the <application>gda-sql</application> and when prompted
+      enter the requested passphrase, as:
+      <programlisting><![CDATA[prompt> gda-sql-4.0 "SQLCipher://DB_NAME=testcrypt"
+Welcome to the GDA SQL console, version 4.1.11
+
+Type: .copyright to show usage and distribution terms
+      .? for help with internal commands
+      .q (or CTRL-D) to quit
+      (the '.' can be replaced by a '\')
+      or any query terminated by a semicolon
+
+Opening connection 'c0' for: SQLCipher://DB_NAME=testcrypt
+	Password for 'c0':]]></programlisting>
+    </para>
+  </sect2>
+  <sect2>
+    <title>How to encrypt an existing database</title>
+    <para>
+      To encrypt an existing database, connect to the database using the SQLCipher provider and execute the
+      following SQL command (replace the passphrase with the requested passphrase):
+      <programlisting>PRAGMA key = 'passphrase';</programlisting>
+      setting the requested passphrase which will be later required to reopen the database. This step
+      prevents opening the database file by the "standard" SQLite provider.
+    </para>
+  </sect2>
+  <sect2>
+    <title>How to change the passphrase of an encrypted database</title>
+    <para>
+      To change an encrypted database's passphrase, open a connection to the database and enter the following
+      SQL command (replace the passphrase with the requested new passphrase):
+      <programlisting>PRAGMA rekey = 'passphrase';</programlisting>
+    </para>
+  </sect2>
+  </sect1>
   
 </chapter>
diff --git a/libgda/sqlite/Makefile.am b/libgda/sqlite/Makefile.am
index 703ccea..0c0f4b6 100644
--- a/libgda/sqlite/Makefile.am
+++ b/libgda/sqlite/Makefile.am
@@ -10,7 +10,7 @@ sqliteinc= -I$(top_srcdir)/libgda/sqlite/sqlite-src \
 endif
 SUBDIRS+= virtual
 
-noinst_LTLIBRARIES = libgda-sqlite.la
+noinst_LTLIBRARIES = libgda-sqlite.la libgda-sqlcipher.la
 if BDBSQL
 noinst_LTLIBRARIES += libgda-bdbsqlite.la
 endif
@@ -63,7 +63,7 @@ libgda_sqlite_la_SOURCES = \
 	gda-symbols-util.h \
 	gda-symbols-util.c
 
-libgda_sqlite_la_CFLAGS = -DSEARCH_LIB_PATH=\""$(SQLITE_PATH)"\"
+libgda_sqlite_la_CFLAGS = -DSEARCH_LIB_PATH=\""$(SQLITE_PATH)"\" -DCLASS_PREFIX=\""GdaSqlite"\"
 libgda_sqlite_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
 libgda_sqlite_la_LIBADD = \
 	virtual/libgda-virtual-4.0.la \
@@ -94,10 +94,38 @@ libgda_bdbsqlite_la_SOURCES = \
 	gda-symbols-util.h \
 	gda-symbols-util.c
 
-libgda_bdbsqlite_la_CFLAGS = $(BDBSQL_CFLAGS) -DWITH_BDBSQLITE -DSEARCH_LIB_PATH=\""$(BDBSQL_PATH)"\"
+libgda_bdbsqlite_la_CFLAGS = $(BDBSQL_CFLAGS) -DWITH_BDBSQLITE -DCLASS_PREFIX=\""GdaDBDSql"\" -DSEARCH_LIB_PATH=\""$(BDBSQL_PATH)"\"
 libgda_bdbsqlite_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
 libgda_bdbsqlite_la_LIBADD = 
 
+libgda_sqlcipher_la_SOURCES = \
+	$(sqliteheaders) \
+	gda-sqlite-blob-op.c \
+	gda-sqlite-blob-op.h \
+	gda-sqlite-ddl.c \
+	gda-sqlite-ddl.h \
+	gda-sqlite-handler-bin.c \
+	gda-sqlite-handler-bin.h \
+	gda-sqlite-handler-boolean.c \
+	gda-sqlite-handler-boolean.h \
+	gda-sqlite-meta.c \
+	gda-sqlite-meta.h \
+	gda-sqlite-provider.c \
+	gda-sqlite-pstmt.h \
+	gda-sqlite-pstmt.c \
+	gda-sqlite-recordset.c \
+	gda-sqlite-recordset.h \
+	gda-sqlite-util.c \
+	gda-sqlite-util.h \
+	gda-sqlite.h \
+	keywords_hash.h \
+	gda-symbols-util.h \
+	gda-symbols-util.c
+
+libgda_sqlcipher_la_CFLAGS = -DSTATIC_SQLITE -DSQLITE_HAS_CODEC -DCLASS_PREFIX=\""GdaSQLCipher"\" -DSEARCH_LIB_PATH=\"""\"
+libgda_sqlcipher_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
+libgda_sqlcipher_la_LIBADD = 
+
 gdaincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/sqlite
 gdainclude_HEADERS=$(sqliteheaders)
 
diff --git a/libgda/sqlite/gda-sqlite-blob-op.c b/libgda/sqlite/gda-sqlite-blob-op.c
index 751ceeb..24d7b3f 100644
--- a/libgda/sqlite/gda-sqlite-blob-op.c
+++ b/libgda/sqlite/gda-sqlite-blob-op.c
@@ -65,11 +65,7 @@ _gda_sqlite_blob_op_get_type (void)
 		};
 		g_static_mutex_lock (&registering);
 		if (type == 0)
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaDBDSqlBlobOp", &info, 0);
-#else
-			type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaSqliteBlobOp", &info, 0);
-#endif
+			type = g_type_register_static (GDA_TYPE_BLOB_OP, CLASS_PREFIX "BlobOp", &info, 0);
 		g_static_mutex_unlock (&registering);
 	}
 	return type;
diff --git a/libgda/sqlite/gda-sqlite-handler-bin.c b/libgda/sqlite/gda-sqlite-handler-bin.c
index de9eaa0..ff0437b 100644
--- a/libgda/sqlite/gda-sqlite-handler-bin.c
+++ b/libgda/sqlite/gda-sqlite-handler-bin.c
@@ -76,11 +76,7 @@ _gda_sqlite_handler_bin_get_type (void)
 
 		g_static_mutex_lock (&registering);
 		if (type == 0) {
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaDBDSqlHandlerBin", &info, 0);
-#else
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaSqliteHandlerBin", &info, 0);
-#endif
+			type = g_type_register_static (G_TYPE_OBJECT, CLASS_PREFIX "HandlerBin", &info, 0);
 			g_type_add_interface_static (type, GDA_TYPE_DATA_HANDLER, &data_entry_info);
 		}
 		g_static_mutex_unlock (&registering);
diff --git a/libgda/sqlite/gda-sqlite-handler-boolean.c b/libgda/sqlite/gda-sqlite-handler-boolean.c
index ecc6141..a644e4c 100644
--- a/libgda/sqlite/gda-sqlite-handler-boolean.c
+++ b/libgda/sqlite/gda-sqlite-handler-boolean.c
@@ -78,11 +78,7 @@ _gda_sqlite_handler_boolean_get_type (void)
 
 		g_static_mutex_lock (&registering);
 		if (type == 0) {
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaDBDSqlHandlerBoolean", &info, 0);
-#else
-			type = g_type_register_static (G_TYPE_OBJECT, "GdaSqliteHandlerBoolean", &info, 0);
-#endif
+			type = g_type_register_static (G_TYPE_OBJECT, CLASS_PREFIX "HandlerBoolean", &info, 0);
 			g_type_add_interface_static (type, GDA_TYPE_DATA_HANDLER, &data_entry_info);
 		}
 		g_static_mutex_unlock (&registering);
diff --git a/libgda/sqlite/gda-sqlite-provider.c b/libgda/sqlite/gda-sqlite-provider.c
index 75df1ff..a65c3b7 100644
--- a/libgda/sqlite/gda-sqlite-provider.c
+++ b/libgda/sqlite/gda-sqlite-provider.c
@@ -496,20 +496,24 @@ gda_sqlite_provider_get_type (void)
 		g_static_mutex_lock (&registering);
 		if (type == 0) {
 #ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaDBDSqlProvider", &info, 0);
+			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
 #else
-  #ifdef HAVE_SQLITE
+  #ifdef STATIC_SQLITE
+			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
+  #else
+    #ifdef HAVE_SQLITE
 			GModule *module2;
 			
 			module2 = find_sqlite_library ("libsqlite3");
 			if (module2)
 				load_symbols (module2);
 			if (s3r)
-				type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaSqliteProvider", &info, 0);
+				type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
 			else
 				g_warning (_("Can't find libsqlite3." G_MODULE_SUFFIX " file."));
-  #else
-			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaSqliteProvider", &info, 0);
+    #else
+			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, CLASS_PREFIX "Provider", &info, 0);
+    #endif
   #endif
 #endif
 		}
@@ -552,6 +556,7 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
 	gint errmsg;
 	SqliteConnectionData *cdata;
 	gchar *dup = NULL;
+	const gchar *passphrase = NULL;
 
 	g_return_val_if_fail (GDA_IS_SQLITE_PROVIDER (provider), FALSE);
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
@@ -571,6 +576,8 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
 	is_virtual = gda_quark_list_find (params, "_IS_VIRTUAL");
 	with_fk = gda_quark_list_find (params, "FK");
 	use_extra_functions = gda_quark_list_find (params, "LOAD_GDA_FUNCTIONS");
+	if (auth)
+		passphrase = gda_quark_list_find (auth, "PASSWORD");
 
 	if (! is_virtual) {
 		if (!dbname) {
@@ -667,6 +674,18 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
 		return FALSE;
 	}
 
+#ifdef SQLITE_HAS_CODEC
+	if (passphrase && *passphrase && SQLITE3_CALL (sqlite3_key)) {
+		errmsg = SQLITE3_CALL (sqlite3_key) (cdata->connection, (void*) passphrase, strlen (passphrase));
+		if (errmsg != SQLITE_OK) {
+			gda_connection_add_event_string (cnc, _("Wrong encryption passphrase"));
+			gda_sqlite_free_cnc_data (cdata);
+			g_static_rec_mutex_unlock (&cnc_mutex);
+			return FALSE;
+		}
+	}
+#endif
+
 	gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_sqlite_free_cnc_data);
 
 	/* use extended result codes */
diff --git a/libgda/sqlite/gda-sqlite-pstmt.c b/libgda/sqlite/gda-sqlite-pstmt.c
index 2341fd5..20d0496 100644
--- a/libgda/sqlite/gda-sqlite-pstmt.c
+++ b/libgda/sqlite/gda-sqlite-pstmt.c
@@ -57,11 +57,7 @@ _gda_sqlite_pstmt_get_type (void)
 
 		g_static_mutex_lock (&registering);
 		if (type == 0)
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_PSTMT, "GdaDBDSqlPStmt", &info, 0);
-#else
-			type = g_type_register_static (GDA_TYPE_PSTMT, "GdaSqlitePStmt", &info, 0);
-#endif
+			type = g_type_register_static (GDA_TYPE_PSTMT, CLASS_PREFIX "PStmt", &info, 0);
 		g_static_mutex_unlock (&registering);
 	}
 	return type;
diff --git a/libgda/sqlite/gda-sqlite-recordset.c b/libgda/sqlite/gda-sqlite-recordset.c
index 6ae3fa6..8a19b13 100644
--- a/libgda/sqlite/gda-sqlite-recordset.c
+++ b/libgda/sqlite/gda-sqlite-recordset.c
@@ -132,11 +132,7 @@ _gda_sqlite_recordset_get_type (void)
 		};
 		g_static_mutex_lock (&registering);
 		if (type == 0)
-#ifdef WITH_BDBSQLITE
-			type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaDBDSqlRecordset", &info, 0);
-#else
-			type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaSqliteRecordset", &info, 0);
-#endif
+			type = g_type_register_static (GDA_TYPE_DATA_SELECT, CLASS_PREFIX "Recordset", &info, 0);
 		g_static_mutex_unlock (&registering);
 	}
 
diff --git a/libgda/sqlite/gda-sqlite.h b/libgda/sqlite/gda-sqlite.h
index 16b1a7a..3a7298d 100644
--- a/libgda/sqlite/gda-sqlite.h
+++ b/libgda/sqlite/gda-sqlite.h
@@ -33,16 +33,21 @@
   #include "gda-symbols-util.h"
   #define SQLITE3_CALL(x) (s3r->x)
 #else
-  #ifdef HAVE_SQLITE
-    #include <sqlite3.h>
-    #include "gda-symbols-util.h"
-    #define SQLITE3_CALL(x) (s3r->x)
-    #if (SQLITE_VERSION_NUMBER < 3005000)
-      typedef sqlite_int64 sqlite3_int64;
-    #endif
-  #else
+  #ifdef STATIC_SQLITE
     #include "sqlite-src/sqlite3.h"
     #define SQLITE3_CALL(x) (x)
+  #else
+    #ifdef HAVE_SQLITE
+      #include <sqlite3.h>
+      #include "gda-symbols-util.h"
+      #define SQLITE3_CALL(x) (s3r->x)
+      #if (SQLITE_VERSION_NUMBER < 3005000)
+        typedef sqlite_int64 sqlite3_int64;
+      #endif
+    #else
+      #include "sqlite-src/sqlite3.h"
+      #define SQLITE3_CALL(x) (x)
+    #endif
   #endif
 #endif
 
diff --git a/libgda/sqlite/gda-symbols-util.c b/libgda/sqlite/gda-symbols-util.c
index 1da7dcc..a043934 100644
--- a/libgda/sqlite/gda-symbols-util.c
+++ b/libgda/sqlite/gda-symbols-util.c
@@ -271,6 +271,10 @@ load_symbols (GModule *module)
 		goto onerror;
 	if (! g_module_symbol (module, "sqlite3_value_type", (gpointer*) &(s3r->sqlite3_value_type)))
 		goto onerror;
+	if (! g_module_symbol (module, "sqlite3_key", (gpointer*) &(s3r->sqlite3_key)))
+		s3r->sqlite3_key = NULL;
+	if (! g_module_symbol (module, "sqlite3_rekey", (gpointer*) &(s3r->sqlite3_key)))
+		s3r->sqlite3_rekey = NULL;
 	return;
 
  onerror:
diff --git a/libgda/sqlite/gda-symbols-util.h b/libgda/sqlite/gda-symbols-util.h
index 6f929e8..b543740 100644
--- a/libgda/sqlite/gda-symbols-util.h
+++ b/libgda/sqlite/gda-symbols-util.h
@@ -106,6 +106,9 @@ typedef struct {
 	int  (*sqlite3_value_int)(sqlite3_value*);
 	const unsigned char * (*sqlite3_value_text)(sqlite3_value*);
 	int  (*sqlite3_value_type)(sqlite3_value*);
+
+	int  (*sqlite3_key)(sqlite3 *, const void *, int);
+	int  (*sqlite3_rekey)(sqlite3 *, const void *, int);
 } Sqlite3ApiRoutines;
 
 extern Sqlite3ApiRoutines *s3r;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4826287..bcb9f58 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -203,6 +203,19 @@ providers/reuseable/mysql/gda-mysql-meta.c
 providers/reuseable/mysql/gda-mysql-reuseable.c
 providers/reuseable/postgres/gda-postgres-meta.c
 providers/reuseable/postgres/gda-postgres-reuseable.c
+providers/sqlcipher/libmain.c
+providers/sqlcipher/sqlcipher_specs_add_column.xml.in
+providers/sqlcipher/sqlcipher_specs_auth.xml.in
+providers/sqlcipher/sqlcipher_specs_create_db.xml.in
+providers/sqlcipher/sqlcipher_specs_create_index.xml.in
+providers/sqlcipher/sqlcipher_specs_create_table.xml.in
+providers/sqlcipher/sqlcipher_specs_create_view.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_db.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_index.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_table.xml.in
+providers/sqlcipher/sqlcipher_specs_drop_view.xml.in
+providers/sqlcipher/sqlcipher_specs_dsn.xml.in
+providers/sqlcipher/sqlcipher_specs_rename_table.xml.in
 providers/sqlite/libmain.c
 providers/sqlite/sqlite_specs_add_column.xml.in
 providers/sqlite/sqlite_specs_create_db.xml.in
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 3d3762d..84bab04 100755
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -49,6 +49,7 @@ providers/skel-implementation/capi/libmain.c
 providers/skel-implementation/models/gda-models-provider.c
 providers/skel-implementation/models/libmain.c
 providers/skel-implementation/models/models_specs_dsn.xml.in
+providers/sqlcipher/sqlite3.c
 providers/sybase/gda-sybase-provider.c
 providers/sybase/gda-sybase-recordset.c
 providers/sybase/gda-sybase-types.c
diff --git a/providers/Makefile.am b/providers/Makefile.am
index b5fce61..c783825 100644
--- a/providers/Makefile.am
+++ b/providers/Makefile.am
@@ -62,6 +62,10 @@ if LIBSOUP
 GDA_WEB_SERVER=web
 endif
 
+if HAVE_LIBCRYPTO
+GDA_SQLCIPHER_SERVER=sqlcipher
+endif
+
 SUBDIRS = \
 	reuseable \
 	sqlite \
@@ -73,7 +77,8 @@ SUBDIRS = \
 	$(GDA_MYSQL_SERVER) \
 	$(GDA_JAVA_SERVER) \
 	$(GDA_ORACLE_SERVER) \
-	$(GDA_WEB_SERVER)
+	$(GDA_WEB_SERVER) \
+	$(GDA_SQLCIPHER_SERVER)
 #	$(GDA_FREETDS_SERVER) \
 #	$(GDA_IBMDB2_SERVER) \
 #	$(GDA_FIREBIRD_SERVER) \
diff --git a/providers/sqlcipher/.gitignore b/providers/sqlcipher/.gitignore
new file mode 100644
index 0000000..c989ca2
--- /dev/null
+++ b/providers/sqlcipher/.gitignore
@@ -0,0 +1,2 @@
+sqlite3.c
+sqlite3.h
\ No newline at end of file
diff --git a/providers/sqlcipher/COPYING.sqlcipher b/providers/sqlcipher/COPYING.sqlcipher
new file mode 100644
index 0000000..b6e96ae
--- /dev/null
+++ b/providers/sqlcipher/COPYING.sqlcipher
@@ -0,0 +1,28 @@
+Please find below the licence under which SQLCipher is distributed
+------------------------------------------------------------------
+
+
+Copyright (c) 2008, ZETETIC LLC
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the ZETETIC LLC nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/providers/sqlcipher/Makefile.am b/providers/sqlcipher/Makefile.am
new file mode 100644
index 0000000..c835e4c
--- /dev/null
+++ b/providers/sqlcipher/Makefile.am
@@ -0,0 +1,57 @@
+providerdir=$(libdir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/providers
+provider_LTLIBRARIES = libgda-sqlcipher.la
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/libgda \
+	-I$(top_srcdir)/libgda/sqlite \
+	-I$(top_builddir) \
+	$(LIBGDA_CFLAGS) \
+	$(LIBCRYPTO_CFLAGS) \
+	$(sqliteinc) \
+	-DSQLITE_HAS_CODEC -DSQLITE_API= -DSQLITE_PRIVATE= -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_THREADSAFE=1 -DSQLITE_OMIT_LOAD_EXTENSION=1
+
+sqlite_sources = sqlite3.c sqlite3.h
+$(sqlite_sources): sqlcipher.patch $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.c $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.h
+	cp $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.c sqlite3.c
+	cp $(top_srcdir)/libgda/sqlite/sqlite-src/sqlite3.h sqlite3.h
+	patch -p 0 < sqlcipher.patch
+
+libgda_sqlcipher_la_SOURCES = \
+	$(sqlite_sources) \
+	libmain.c
+
+libgda_sqlcipher_la_LDFLAGS = -export-dynamic -module -avoid-version $(LIBTOOL_PROV_EXPORT_OPTIONS)
+libgda_sqlcipher_la_LIBADD = \
+	$(top_builddir)/libgda/sqlite/libgda-sqlcipher.la \
+	$(LIBCRYPTO_LIBS)
+
+xmldir   = $(datadir)/libgda-4.0
+xml_in_files = \
+	sqlcipher_specs_auth.xml.in \
+	sqlcipher_specs_dsn.xml.in \
+	sqlcipher_specs_create_db.xml.in \
+	sqlcipher_specs_drop_db.xml.in \
+	sqlcipher_specs_create_table.xml.in \
+	sqlcipher_specs_drop_table.xml.in \
+	sqlcipher_specs_create_index.xml.in \
+	sqlcipher_specs_drop_index.xml.in \
+	sqlcipher_specs_rename_table.xml.in \
+	sqlcipher_specs_add_column.xml.in \
+	sqlcipher_specs_create_view.xml.in \
+	sqlcipher_specs_drop_view.xml.in
+
+ INTLTOOL_XML_RULE@
+
+xml_DATA = $(xml_in_files:.xml.in=.xml)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libgda-sqlcipher-4.0.pc
+
+EXTRA_DIST = $(xml_in_files) \
+	libgda-sqlcipher-4.0.pc.in \
+	sqlcipher.patch
+
+CLEANFILES = $(sqlite_sources)
+
+DISTCLEANFILES = $(xml_DATA)
diff --git a/providers/sqlcipher/NOTE_for_new_SQLCipher_version b/providers/sqlcipher/NOTE_for_new_SQLCipher_version
new file mode 100644
index 0000000..845bbb0
--- /dev/null
+++ b/providers/sqlcipher/NOTE_for_new_SQLCipher_version
@@ -0,0 +1,17 @@
+To upgrade SQLCipher version, all is needed is to create a patch against
+the sqlite3.c and sqlite3.h files in ${top_srcdir}/libgda/sqlite/sqlite-src
+and replace the sqlcipher.patch file:
+
+
+* define the LIBGDA_SOURCE_DIR to point to the top source directory where Libgda's files are
+* download the SQLCipher code source and extract (from http://www.zetetic.net/code/sqlcipher or
+  http://www.zetetic.net/code/sqlcipher)
+* into the extracted archive, run:
+  ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC"
+  make sqlite3.c
+  cp $LIBGDA_SOURCE_DIR/libgda/sqlite/sqlite-src/sqlite3.c sqlite3.c.sqlite
+  cp $LIBGDA_SOURCE_DIR/libgda/sqlite/sqlite-src/sqlite3.h sqlite3.h.sqlite
+  diff -u sqlite3.h.sqlite sqlite3.h > sqlcipher.patch
+  diff -u sqlite3.c.sqlite sqlite3.c >> sqlcipher.patch
+  mv sqlcipher.patch $LIBGDA_SOURCE_DIR/providers/sqlcipher/
+* you can now delete all these temporary files
\ No newline at end of file
diff --git a/providers/sqlcipher/libgda-sqlcipher-4.0.pc.in b/providers/sqlcipher/libgda-sqlcipher-4.0.pc.in
new file mode 100644
index 0000000..72d2e7c
--- /dev/null
+++ b/providers/sqlcipher/libgda-sqlcipher-4.0.pc.in
@@ -0,0 +1,9 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+
+Name: libgda-bdbsql- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
+Description: GDA (GNOME Data Access) BDBSql provider
+Requires: libgda- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
+Version: @VERSION@
diff --git a/providers/sqlcipher/libmain.c b/providers/sqlcipher/libmain.c
new file mode 100644
index 0000000..3105c96
--- /dev/null
+++ b/providers/sqlcipher/libmain.c
@@ -0,0 +1,105 @@
+/* GDA
+ * Copyright (C) 2010 The GNOME Foundation
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <libgda/gda-config.h>
+#include "gda-sqlite-provider.h"
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/binreloc/gda-binreloc.h>
+#include <libgda/sqlite/gda-symbols-util.h>
+
+static gchar      *module_path = NULL;
+const gchar       *plugin_get_name (void);
+const gchar       *plugin_get_description (void);
+gchar             *plugin_get_dsn_spec (void);
+GdaServerProvider *plugin_create_provider (void);
+
+/*
+ * Functions executed when calling g_module_open() and g_module_close()
+ */
+const gchar *
+g_module_check_init (GModule *module)
+{
+        /*g_module_make_resident (module);*/
+        return NULL;
+}
+
+void
+g_module_unload (GModule *module)
+{
+        g_free (module_path);
+        module_path = NULL;
+}
+
+/*
+ * Normal plugin functions 
+ */
+void
+plugin_init (const gchar *real_path)
+{
+        if (real_path)
+                module_path = g_strdup (real_path);
+}
+
+const gchar *
+plugin_get_name (void)
+{
+	return "SQLCipher";
+}
+
+const gchar *
+plugin_get_description (void)
+{
+	return _("Provider for SQLCipher");
+}
+
+gchar *
+plugin_get_dsn_spec (void)
+{
+	gchar *ret, *dir;
+
+	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
+	ret = gda_server_provider_load_file_contents (module_path, dir, "sqlcipher_specs_dsn.xml");
+	g_free (dir);
+	return ret;
+}
+
+gchar *
+plugin_get_auth_spec (void)
+{
+	gchar *ret, *dir;
+
+        dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
+        ret = gda_server_provider_load_file_contents (module_path, dir, "sqlcipher_specs_auth.xml");
+        g_free (dir);
+        return ret;
+}
+
+GdaServerProvider *
+plugin_create_provider (void)
+{
+	GdaServerProvider *prov;
+
+	prov = (GdaServerProvider*) g_object_new (GDA_TYPE_SQLITE_PROVIDER, NULL);
+        g_object_set_data ((GObject *) prov, "GDA_PROVIDER_DIR", module_path);
+        return prov;
+}
diff --git a/providers/sqlcipher/sqlcipher.patch b/providers/sqlcipher/sqlcipher.patch
new file mode 100644
index 0000000..77d2090
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher.patch
@@ -0,0 +1,2483 @@
+--- sqlite3.c.sqlite	2010-09-13 21:54:33.000000000 +0200
++++ sqlite3.c	2010-09-13 21:51:52.000000000 +0200
+@@ -10994,6 +10994,1320 @@
+ #endif /* _SQLITEINT_H_ */
+ 
+ /************** End of sqliteInt.h *******************************************/
++/************** Begin file crypto.c ******************************************/
++/* 
++** SQLCipher
++** crypto.c developed by Stephen Lombardo (Zetetic LLC) 
++** sjlombardo at zetetic dot net
++** http://zetetic.net
++** 
++** Copyright (c) 2009, ZETETIC LLC
++** All rights reserved.
++** 
++** Redistribution and use in source and binary forms, with or without
++** modification, are permitted provided that the following conditions are met:
++**     * Redistributions of source code must retain the above copyright
++**       notice, this list of conditions and the following disclaimer.
++**     * Redistributions in binary form must reproduce the above copyright
++**       notice, this list of conditions and the following disclaimer in the
++**       documentation and/or other materials provided with the distribution.
++**     * Neither the name of the ZETETIC LLC nor the
++**       names of its contributors may be used to endorse or promote products
++**       derived from this software without specific prior written permission.
++** 
++** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
++** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++**  
++*/
++/* BEGIN CRYPTO */
++#ifdef SQLITE_HAS_CODEC
++
++#include <openssl/evp.h>
++#include <openssl/rand.h>
++#include <openssl/hmac.h>
++/************** Include btreeInt.h in the middle of crypto.c *****************/
++/************** Begin file btreeInt.h ****************************************/
++/*
++** 2004 April 6
++**
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
++**
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
++**
++*************************************************************************
++** This file implements a external (disk-based) database using BTrees.
++** For a detailed discussion of BTrees, refer to
++**
++**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
++**     "Sorting And Searching", pages 473-480. Addison-Wesley
++**     Publishing Company, Reading, Massachusetts.
++**
++** The basic idea is that each page of the file contains N database
++** entries and N+1 pointers to subpages.
++**
++**   ----------------------------------------------------------------
++**   |  Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
++**   ----------------------------------------------------------------
++**
++** All of the keys on the page that Ptr(0) points to have values less
++** than Key(0).  All of the keys on page Ptr(1) and its subpages have
++** values greater than Key(0) and less than Key(1).  All of the keys
++** on Ptr(N) and its subpages have values greater than Key(N-1).  And
++** so forth.
++**
++** Finding a particular key requires reading O(log(M)) pages from the 
++** disk where M is the number of entries in the tree.
++**
++** In this implementation, a single file can hold one or more separate 
++** BTrees.  Each BTree is identified by the index of its root page.  The
++** key and data for any entry are combined to form the "payload".  A
++** fixed amount of payload can be carried directly on the database
++** page.  If the payload is larger than the preset amount then surplus
++** bytes are stored on overflow pages.  The payload for an entry
++** and the preceding pointer are combined to form a "Cell".  Each 
++** page has a small header which contains the Ptr(N) pointer and other
++** information such as the size of key and data.
++**
++** FORMAT DETAILS
++**
++** The file is divided into pages.  The first page is called page 1,
++** the second is page 2, and so forth.  A page number of zero indicates
++** "no such page".  The page size can be any power of 2 between 512 and 65536.
++** Each page can be either a btree page, a freelist page, an overflow
++** page, or a pointer-map page.
++**
++** The first page is always a btree page.  The first 100 bytes of the first
++** page contain a special header (the "file header") that describes the file.
++** The format of the file header is as follows:
++**
++**   OFFSET   SIZE    DESCRIPTION
++**      0      16     Header string: "SQLite format 3\000"
++**     16       2     Page size in bytes.  
++**     18       1     File format write version
++**     19       1     File format read version
++**     20       1     Bytes of unused space at the end of each page
++**     21       1     Max embedded payload fraction
++**     22       1     Min embedded payload fraction
++**     23       1     Min leaf payload fraction
++**     24       4     File change counter
++**     28       4     Reserved for future use
++**     32       4     First freelist page
++**     36       4     Number of freelist pages in the file
++**     40      60     15 4-byte meta values passed to higher layers
++**
++**     40       4     Schema cookie
++**     44       4     File format of schema layer
++**     48       4     Size of page cache
++**     52       4     Largest root-page (auto/incr_vacuum)
++**     56       4     1=UTF-8 2=UTF16le 3=UTF16be
++**     60       4     User version
++**     64       4     Incremental vacuum mode
++**     68       4     unused
++**     72       4     unused
++**     76       4     unused
++**
++** All of the integer values are big-endian (most significant byte first).
++**
++** The file change counter is incremented when the database is changed
++** This counter allows other processes to know when the file has changed
++** and thus when they need to flush their cache.
++**
++** The max embedded payload fraction is the amount of the total usable
++** space in a page that can be consumed by a single cell for standard
++** B-tree (non-LEAFDATA) tables.  A value of 255 means 100%.  The default
++** is to limit the maximum cell size so that at least 4 cells will fit
++** on one page.  Thus the default max embedded payload fraction is 64.
++**
++** If the payload for a cell is larger than the max payload, then extra
++** payload is spilled to overflow pages.  Once an overflow page is allocated,
++** as many bytes as possible are moved into the overflow pages without letting
++** the cell size drop below the min embedded payload fraction.
++**
++** The min leaf payload fraction is like the min embedded payload fraction
++** except that it applies to leaf nodes in a LEAFDATA tree.  The maximum
++** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
++** not specified in the header.
++**
++** Each btree pages is divided into three sections:  The header, the
++** cell pointer array, and the cell content area.  Page 1 also has a 100-byte
++** file header that occurs before the page header.
++**
++**      |----------------|
++**      | file header    |   100 bytes.  Page 1 only.
++**      |----------------|
++**      | page header    |   8 bytes for leaves.  12 bytes for interior nodes
++**      |----------------|
++**      | cell pointer   |   |  2 bytes per cell.  Sorted order.
++**      | array          |   |  Grows downward
++**      |                |   v
++**      |----------------|
++**      | unallocated    |
++**      | space          |
++**      |----------------|   ^  Grows upwards
++**      | cell content   |   |  Arbitrary order interspersed with freeblocks.
++**      | area           |   |  and free space fragments.
++**      |----------------|
++**
++** The page headers looks like this:
++**
++**   OFFSET   SIZE     DESCRIPTION
++**      0       1      Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
++**      1       2      byte offset to the first freeblock
++**      3       2      number of cells on this page
++**      5       2      first byte of the cell content area
++**      7       1      number of fragmented free bytes
++**      8       4      Right child (the Ptr(N) value).  Omitted on leaves.
++**
++** The flags define the format of this btree page.  The leaf flag means that
++** this page has no children.  The zerodata flag means that this page carries
++** only keys and no data.  The intkey flag means that the key is a integer
++** which is stored in the key size entry of the cell header rather than in
++** the payload area.
++**
++** The cell pointer array begins on the first byte after the page header.
++** The cell pointer array contains zero or more 2-byte numbers which are
++** offsets from the beginning of the page to the cell content in the cell
++** content area.  The cell pointers occur in sorted order.  The system strives
++** to keep free space after the last cell pointer so that new cells can
++** be easily added without having to defragment the page.
++**
++** Cell content is stored at the very end of the page and grows toward the
++** beginning of the page.
++**
++** Unused space within the cell content area is collected into a linked list of
++** freeblocks.  Each freeblock is at least 4 bytes in size.  The byte offset
++** to the first freeblock is given in the header.  Freeblocks occur in
++** increasing order.  Because a freeblock must be at least 4 bytes in size,
++** any group of 3 or fewer unused bytes in the cell content area cannot
++** exist on the freeblock chain.  A group of 3 or fewer free bytes is called
++** a fragment.  The total number of bytes in all fragments is recorded.
++** in the page header at offset 7.
++**
++**    SIZE    DESCRIPTION
++**      2     Byte offset of the next freeblock
++**      2     Bytes in this freeblock
++**
++** Cells are of variable length.  Cells are stored in the cell content area at
++** the end of the page.  Pointers to the cells are in the cell pointer array
++** that immediately follows the page header.  Cells is not necessarily
++** contiguous or in order, but cell pointers are contiguous and in order.
++**
++** Cell content makes use of variable length integers.  A variable
++** length integer is 1 to 9 bytes where the lower 7 bits of each 
++** byte are used.  The integer consists of all bytes that have bit 8 set and
++** the first byte with bit 8 clear.  The most significant byte of the integer
++** appears first.  A variable-length integer may not be more than 9 bytes long.
++** As a special case, all 8 bytes of the 9th byte are used as data.  This
++** allows a 64-bit integer to be encoded in 9 bytes.
++**
++**    0x00                      becomes  0x00000000
++**    0x7f                      becomes  0x0000007f
++**    0x81 0x00                 becomes  0x00000080
++**    0x82 0x00                 becomes  0x00000100
++**    0x80 0x7f                 becomes  0x0000007f
++**    0x8a 0x91 0xd1 0xac 0x78  becomes  0x12345678
++**    0x81 0x81 0x81 0x81 0x01  becomes  0x10204081
++**
++** Variable length integers are used for rowids and to hold the number of
++** bytes of key and data in a btree cell.
++**
++** The content of a cell looks like this:
++**
++**    SIZE    DESCRIPTION
++**      4     Page number of the left child. Omitted if leaf flag is set.
++**     var    Number of bytes of data. Omitted if the zerodata flag is set.
++**     var    Number of bytes of key. Or the key itself if intkey flag is set.
++**      *     Payload
++**      4     First page of the overflow chain.  Omitted if no overflow
++**
++** Overflow pages form a linked list.  Each page except the last is completely
++** filled with data (pagesize - 4 bytes).  The last page can have as little
++** as 1 byte of data.
++**
++**    SIZE    DESCRIPTION
++**      4     Page number of next overflow page
++**      *     Data
++**
++** Freelist pages come in two subtypes: trunk pages and leaf pages.  The
++** file header points to the first in a linked list of trunk page.  Each trunk
++** page points to multiple leaf pages.  The content of a leaf page is
++** unspecified.  A trunk page looks like this:
++**
++**    SIZE    DESCRIPTION
++**      4     Page number of next trunk page
++**      4     Number of leaf pointers on this page
++**      *     zero or more pages numbers of leaves
++*/
++
++
++/* The following value is the maximum cell size assuming a maximum page
++** size give above.
++*/
++#define MX_CELL_SIZE(pBt)  (pBt->pageSize-8)
++
++/* The maximum number of cells on a single page of the database.  This
++** assumes a minimum cell size of 6 bytes  (4 bytes for the cell itself
++** plus 2 bytes for the index to the cell in the page header).  Such
++** small cells will be rare, but they are possible.
++*/
++#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
++
++/* Forward declarations */
++typedef struct MemPage MemPage;
++typedef struct BtLock BtLock;
++
++/*
++** This is a magic string that appears at the beginning of every
++** SQLite database in order to identify the file as a real database.
++**
++** You can change this value at compile-time by specifying a
++** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
++** header must be exactly 16 bytes including the zero-terminator so
++** the string itself should be 15 characters long.  If you change
++** the header, then your custom library will not be able to read 
++** databases generated by the standard tools and the standard tools
++** will not be able to read databases created by your custom library.
++*/
++#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
++#  define SQLITE_FILE_HEADER "SQLite format 3"
++#endif
++
++/*
++** Page type flags.  An ORed combination of these flags appear as the
++** first byte of on-disk image of every BTree page.
++*/
++#define PTF_INTKEY    0x01
++#define PTF_ZERODATA  0x02
++#define PTF_LEAFDATA  0x04
++#define PTF_LEAF      0x08
++
++/*
++** As each page of the file is loaded into memory, an instance of the following
++** structure is appended and initialized to zero.  This structure stores
++** information about the page that is decoded from the raw file page.
++**
++** The pParent field points back to the parent page.  This allows us to
++** walk up the BTree from any leaf to the root.  Care must be taken to
++** unref() the parent page pointer when this page is no longer referenced.
++** The pageDestructor() routine handles that chore.
++**
++** Access to all fields of this structure is controlled by the mutex
++** stored in MemPage.pBt->mutex.
++*/
++struct MemPage {
++  u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
++  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
++  u8 intKey;           /* True if intkey flag is set */
++  u8 leaf;             /* True if leaf flag is set */
++  u8 hasData;          /* True if this page stores data */
++  u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
++  u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
++  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
++  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
++  u16 cellOffset;      /* Index in aData of first cell pointer */
++  u16 nFree;           /* Number of free bytes on the page */
++  u16 nCell;           /* Number of cells on this page, local and ovfl */
++  u16 maskPage;        /* Mask for page offset */
++  struct _OvflCell {   /* Cells that will not fit on aData[] */
++    u8 *pCell;          /* Pointers to the body of the overflow cell */
++    u16 idx;            /* Insert this cell before idx-th non-overflow cell */
++  } aOvfl[5];
++  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
++  u8 *aData;           /* Pointer to disk image of the page data */
++  DbPage *pDbPage;     /* Pager page handle */
++  Pgno pgno;           /* Page number for this page */
++};
++
++/*
++** The in-memory image of a disk page has the auxiliary information appended
++** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
++** that extra information.
++*/
++#define EXTRA_SIZE sizeof(MemPage)
++
++/*
++** A linked list of the following structures is stored at BtShared.pLock.
++** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
++** is opened on the table with root page BtShared.iTable. Locks are removed
++** from this list when a transaction is committed or rolled back, or when
++** a btree handle is closed.
++*/
++struct BtLock {
++  Btree *pBtree;        /* Btree handle holding this lock */
++  Pgno iTable;          /* Root page of table */
++  u8 eLock;             /* READ_LOCK or WRITE_LOCK */
++  BtLock *pNext;        /* Next in BtShared.pLock list */
++};
++
++/* Candidate values for BtLock.eLock */
++#define READ_LOCK     1
++#define WRITE_LOCK    2
++
++/* A Btree handle
++**
++** A database connection contains a pointer to an instance of
++** this object for every database file that it has open.  This structure
++** is opaque to the database connection.  The database connection cannot
++** see the internals of this structure and only deals with pointers to
++** this structure.
++**
++** For some database files, the same underlying database cache might be 
++** shared between multiple connections.  In that case, each connection
++** has it own instance of this object.  But each instance of this object
++** points to the same BtShared object.  The database cache and the
++** schema associated with the database file are all contained within
++** the BtShared object.
++**
++** All fields in this structure are accessed under sqlite3.mutex.
++** The pBt pointer itself may not be changed while there exists cursors 
++** in the referenced BtShared that point back to this Btree since those
++** cursors have to do go through this Btree to find their BtShared and
++** they often do so without holding sqlite3.mutex.
++*/
++struct Btree {
++  sqlite3 *db;       /* The database connection holding this btree */
++  BtShared *pBt;     /* Sharable content of this btree */
++  u8 inTrans;        /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
++  u8 sharable;       /* True if we can share pBt with another db */
++  u8 locked;         /* True if db currently has pBt locked */
++  int wantToLock;    /* Number of nested calls to sqlite3BtreeEnter() */
++  int nBackup;       /* Number of backup operations reading this btree */
++  Btree *pNext;      /* List of other sharable Btrees from the same db */
++  Btree *pPrev;      /* Back pointer of the same list */
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  BtLock lock;       /* Object used to lock page 1 */
++#endif
++};
++
++/*
++** Btree.inTrans may take one of the following values.
++**
++** If the shared-data extension is enabled, there may be multiple users
++** of the Btree structure. At most one of these may open a write transaction,
++** but any number may have active read transactions.
++*/
++#define TRANS_NONE  0
++#define TRANS_READ  1
++#define TRANS_WRITE 2
++
++/*
++** An instance of this object represents a single database file.
++** 
++** A single database file can be in use as the same time by two
++** or more database connections.  When two or more connections are
++** sharing the same database file, each connection has it own
++** private Btree object for the file and each of those Btrees points
++** to this one BtShared object.  BtShared.nRef is the number of
++** connections currently sharing this database file.
++**
++** Fields in this structure are accessed under the BtShared.mutex
++** mutex, except for nRef and pNext which are accessed under the
++** global SQLITE_MUTEX_STATIC_MASTER mutex.  The pPager field
++** may not be modified once it is initially set as long as nRef>0.
++** The pSchema field may be set once under BtShared.mutex and
++** thereafter is unchanged as long as nRef>0.
++**
++** isPending:
++**
++**   If a BtShared client fails to obtain a write-lock on a database
++**   table (because there exists one or more read-locks on the table),
++**   the shared-cache enters 'pending-lock' state and isPending is
++**   set to true.
++**
++**   The shared-cache leaves the 'pending lock' state when either of
++**   the following occur:
++**
++**     1) The current writer (BtShared.pWriter) concludes its transaction, OR
++**     2) The number of locks held by other connections drops to zero.
++**
++**   while in the 'pending-lock' state, no connection may start a new
++**   transaction.
++**
++**   This feature is included to help prevent writer-starvation.
++*/
++struct BtShared {
++  Pager *pPager;        /* The page cache */
++  sqlite3 *db;          /* Database connection currently using this Btree */
++  BtCursor *pCursor;    /* A list of all open cursors */
++  MemPage *pPage1;      /* First page of the database */
++  u8 readOnly;          /* True if the underlying file is readonly */
++  u8 pageSizeFixed;     /* True if the page size can no longer be changed */
++  u8 secureDelete;      /* True if secure_delete is enabled */
++  u8 initiallyEmpty;    /* Database is empty at start of transaction */
++#ifndef SQLITE_OMIT_AUTOVACUUM
++  u8 autoVacuum;        /* True if auto-vacuum is enabled */
++  u8 incrVacuum;        /* True if incr-vacuum is enabled */
++#endif
++  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
++  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
++  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
++  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
++  u8 inTransaction;     /* Transaction state */
++  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
++  u32 pageSize;         /* Total number of bytes on a page */
++  u32 usableSize;       /* Number of usable bytes on each page */
++  int nTransaction;     /* Number of open transactions (read + write) */
++  u32 nPage;            /* Number of pages in the database */
++  void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
++  void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
++  sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
++  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
++#ifndef SQLITE_OMIT_SHARED_CACHE
++  int nRef;             /* Number of references to this structure */
++  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
++  BtLock *pLock;        /* List of locks held on this shared-btree struct */
++  Btree *pWriter;       /* Btree with currently open write transaction */
++  u8 isExclusive;       /* True if pWriter has an EXCLUSIVE lock on the db */
++  u8 isPending;         /* If waiting for read-locks to clear */
++#endif
++  u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
++};
++
++/*
++** An instance of the following structure is used to hold information
++** about a cell.  The parseCellPtr() function fills in this structure
++** based on information extract from the raw disk page.
++*/
++typedef struct CellInfo CellInfo;
++struct CellInfo {
++  u8 *pCell;     /* Pointer to the start of cell content */
++  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
++  u32 nData;     /* Number of bytes of data */
++  u32 nPayload;  /* Total amount of payload */
++  u16 nHeader;   /* Size of the cell content header in bytes */
++  u16 nLocal;    /* Amount of payload held locally */
++  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
++  u16 nSize;     /* Size of the cell content on the main b-tree page */
++};
++
++/*
++** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
++** this will be declared corrupt. This value is calculated based on a
++** maximum database size of 2^31 pages a minimum fanout of 2 for a
++** root-node and 3 for all other internal nodes.
++**
++** If a tree that appears to be taller than this is encountered, it is
++** assumed that the database is corrupt.
++*/
++#define BTCURSOR_MAX_DEPTH 20
++
++/*
++** A cursor is a pointer to a particular entry within a particular
++** b-tree within a database file.
++**
++** The entry is identified by its MemPage and the index in
++** MemPage.aCell[] of the entry.
++**
++** A single database file can shared by two more database connections,
++** but cursors cannot be shared.  Each cursor is associated with a
++** particular database connection identified BtCursor.pBtree.db.
++**
++** Fields in this structure are accessed under the BtShared.mutex
++** found at self->pBt->mutex. 
++*/
++struct BtCursor {
++  Btree *pBtree;            /* The Btree to which this cursor belongs */
++  BtShared *pBt;            /* The BtShared this cursor points to */
++  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
++  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
++  Pgno pgnoRoot;            /* The root page of this tree */
++  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
++  CellInfo info;            /* A parse of the cell we are pointing at */
++  u8 wrFlag;                /* True if writable */
++  u8 atLast;                /* Cursor pointing to the last entry */
++  u8 validNKey;             /* True if info.nKey is valid */
++  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
++  void *pKey;      /* Saved key that was cursor's last known position */
++  i64 nKey;        /* Size of pKey, or last integer key */
++  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
++#ifndef SQLITE_OMIT_INCRBLOB
++  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
++  Pgno *aOverflow;          /* Cache of overflow page locations */
++#endif
++  i16 iPage;                            /* Index of current page in apPage */
++  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
++  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
++};
++
++/*
++** Potential values for BtCursor.eState.
++**
++** CURSOR_VALID:
++**   Cursor points to a valid entry. getPayload() etc. may be called.
++**
++** CURSOR_INVALID:
++**   Cursor does not point to a valid entry. This can happen (for example) 
++**   because the table is empty or because BtreeCursorFirst() has not been
++**   called.
++**
++** CURSOR_REQUIRESEEK:
++**   The table that this cursor was opened on still exists, but has been 
++**   modified since the cursor was last used. The cursor position is saved
++**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in 
++**   this state, restoreCursorPosition() can be called to attempt to
++**   seek the cursor to the saved position.
++**
++** CURSOR_FAULT:
++**   A unrecoverable error (an I/O error or a malloc failure) has occurred
++**   on a different connection that shares the BtShared cache with this
++**   cursor.  The error has left the cache in an inconsistent state.
++**   Do nothing else with this cursor.  Any attempt to use the cursor
++**   should return the error code stored in BtCursor.skip
++*/
++#define CURSOR_INVALID           0
++#define CURSOR_VALID             1
++#define CURSOR_REQUIRESEEK       2
++#define CURSOR_FAULT             3
++
++/* 
++** The database page the PENDING_BYTE occupies. This page is never used.
++*/
++# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
++
++/*
++** These macros define the location of the pointer-map entry for a 
++** database page. The first argument to each is the number of usable
++** bytes on each page of the database (often 1024). The second is the
++** page number to look up in the pointer map.
++**
++** PTRMAP_PAGENO returns the database page number of the pointer-map
++** page that stores the required pointer. PTRMAP_PTROFFSET returns
++** the offset of the requested map entry.
++**
++** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
++** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
++** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
++** this test.
++*/
++#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
++#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
++#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
++
++/*
++** The pointer map is a lookup table that identifies the parent page for
++** each child page in the database file.  The parent page is the page that
++** contains a pointer to the child.  Every page in the database contains
++** 0 or 1 parent pages.  (In this context 'database page' refers
++** to any page that is not part of the pointer map itself.)  Each pointer map
++** entry consists of a single byte 'type' and a 4 byte parent page number.
++** The PTRMAP_XXX identifiers below are the valid types.
++**
++** The purpose of the pointer map is to facility moving pages from one
++** position in the file to another as part of autovacuum.  When a page
++** is moved, the pointer in its parent must be updated to point to the
++** new location.  The pointer map is used to locate the parent page quickly.
++**
++** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
++**                  used in this case.
++**
++** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number 
++**                  is not used in this case.
++**
++** PTRMAP_OVERFLOW1: The database page is the first page in a list of 
++**                   overflow pages. The page number identifies the page that
++**                   contains the cell with a pointer to this overflow page.
++**
++** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
++**                   overflow pages. The page-number identifies the previous
++**                   page in the overflow page list.
++**
++** PTRMAP_BTREE: The database page is a non-root btree page. The page number
++**               identifies the parent page in the btree.
++*/
++#define PTRMAP_ROOTPAGE 1
++#define PTRMAP_FREEPAGE 2
++#define PTRMAP_OVERFLOW1 3
++#define PTRMAP_OVERFLOW2 4
++#define PTRMAP_BTREE 5
++
++/* A bunch of assert() statements to check the transaction state variables
++** of handle p (type Btree*) are internally consistent.
++*/
++#define btreeIntegrity(p) \
++  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
++  assert( p->pBt->inTransaction>=p->inTrans ); 
++
++
++/*
++** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
++** if the database supports auto-vacuum or not. Because it is used
++** within an expression that is an argument to another macro 
++** (sqliteMallocRaw), it is not possible to use conditional compilation.
++** So, this macro is defined instead.
++*/
++#ifndef SQLITE_OMIT_AUTOVACUUM
++#define ISAUTOVACUUM (pBt->autoVacuum)
++#else
++#define ISAUTOVACUUM 0
++#endif
++
++
++/*
++** This structure is passed around through all the sanity checking routines
++** in order to keep track of some global state information.
++*/
++typedef struct IntegrityCk IntegrityCk;
++struct IntegrityCk {
++  BtShared *pBt;    /* The tree being checked out */
++  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
++  Pgno nPage;       /* Number of pages in the database */
++  int *anRef;       /* Number of times each page is referenced */
++  int mxErr;        /* Stop accumulating errors when this reaches zero */
++  int nErr;         /* Number of messages written to zErrMsg so far */
++  int mallocFailed; /* A memory allocation error has occurred */
++  StrAccum errMsg;  /* Accumulate the error message text here */
++};
++
++/*
++** Read or write a two- and four-byte big-endian integer values.
++*/
++#define get2byte(x)   ((x)[0]<<8 | (x)[1])
++#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
++#define get4byte sqlite3Get4byte
++#define put4byte sqlite3Put4byte
++
++/************** End of btreeInt.h ********************************************/
++/************** Continuing where we left off in crypto.c *********************/
++/************** Include crypto.h in the middle of crypto.c *******************/
++/************** Begin file crypto.h ******************************************/
++/* 
++** SQLCipher
++** crypto.h developed by Stephen Lombardo (Zetetic LLC) 
++** sjlombardo at zetetic dot net
++** http://zetetic.net
++** 
++** Copyright (c) 2008, ZETETIC LLC
++** All rights reserved.
++** 
++** Redistribution and use in source and binary forms, with or without
++** modification, are permitted provided that the following conditions are met:
++**     * Redistributions of source code must retain the above copyright
++**       notice, this list of conditions and the following disclaimer.
++**     * Redistributions in binary form must reproduce the above copyright
++**       notice, this list of conditions and the following disclaimer in the
++**       documentation and/or other materials provided with the distribution.
++**     * Neither the name of the ZETETIC LLC nor the
++**       names of its contributors may be used to endorse or promote products
++**       derived from this software without specific prior written permission.
++** 
++** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
++** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
++** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++**  
++*/
++/* BEGIN CRYPTO */
++#ifdef SQLITE_HAS_CODEC
++#ifndef CRYPTO_H
++#define CRYPTO_H
++
++#define FILE_HEADER_SZ 16
++
++#ifndef CIPHER
++#define CIPHER "aes-256-cbc"
++#endif
++
++#define CIPHER_DECRYPT 0
++#define CIPHER_ENCRYPT 1
++
++#ifndef PBKDF2_ITER
++#define PBKDF2_ITER 4000
++#endif
++
++SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx);
++SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno);
++SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager);
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
++  Pager *pPager,
++  void *(*xCodec)(void*,void*,Pgno,int),
++  void (*xCodecSizeChng)(void*,int,int),
++  void (*xCodecFree)(void*),
++  void *pCodec
++);
++
++#endif
++#endif
++/* END CRYPTO */
++
++/************** End of crypto.h **********************************************/
++/************** Continuing where we left off in crypto.c *********************/
++
++#ifdef CODEC_DEBUG
++#define CODEC_TRACE(X)  {printf X;fflush(stdout);}
++#else
++#define CODEC_TRACE(X)
++#endif
++
++SQLITE_PRIVATE void sqlite3FreeCodecArg(void *pCodecArg);
++
++typedef struct {
++  int derive_key;
++  EVP_CIPHER *evp_cipher;
++  int kdf_iter;
++  int key_sz;
++  int iv_sz;
++  int pass_sz;
++  unsigned char *key;
++  char *pass;
++} cipher_ctx;
++
++typedef struct {
++  int kdf_salt_sz;
++  int mode_rekey;
++  unsigned char *kdf_salt;
++  unsigned char *buffer;
++  Btree *pBt;
++  cipher_ctx *read_ctx;
++  cipher_ctx *write_ctx;
++} codec_ctx;
++
++static void activate_openssl() {
++  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++  if(EVP_get_cipherbyname(CIPHER) == NULL) {
++    OpenSSL_add_all_algorithms();
++  } 
++  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++
++/*
++**  Simple routines for converting hex char strings to binary data
++ */
++static int cipher_hex2int(char c) {
++  return (c>='0' && c<='9') ? (c)-'0' :
++         (c>='A' && c<='F') ? (c)-'A'+10 :
++         (c>='a' && c<='f') ? (c)-'a'+10 : 0;
++}
++
++static void cipher_hex2bin(const char *hex, int sz, unsigned char *out){
++  int i;
++  for(i = 0; i < sz; i += 2){
++    out[i/2] = (cipher_hex2int(hex[i])<<4) | cipher_hex2int(hex[i+1]);
++  }
++}
++
++
++/**
++  * Free and wipe memory
++  * If ptr is not null memory will be freed. 
++  * If sz is greater than zero, the memory will be overwritten with zero before it is freed
++  */
++static void codec_free(void *ptr, int sz) {
++  if(ptr) {
++    if(sz > 0) memset(ptr, 0, sz); // FIXME - require buffer size
++    sqlite3_free(ptr);
++  }
++}
++
++/**
++  * Set the raw password / key data for a cipher context
++  * 
++  * returns SQLITE_OK if assignment was successfull
++  * returns SQLITE_NOMEM if an error occured allocating memory
++  * returns SQLITE_ERROR if the key couldn't be set because the pass was null or size was zero
++  */
++static int cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) {
++  codec_free(ctx->pass, ctx->pass_sz);
++  ctx->pass_sz = nKey;
++  if(zKey && nKey) {
++    ctx->pass = sqlite3Malloc(nKey);
++    if(ctx->pass == NULL) return SQLITE_NOMEM;
++    memcpy(ctx->pass, zKey, nKey);
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++/**
++  * Initialize a a new cipher_ctx struct. This function will allocate memory
++  * for the cipher context and for the key
++  * 
++  * returns SQLITE_OK if initialization was successful
++  * returns SQLITE_NOMEM if an error occured allocating memory
++  */
++static int cipher_ctx_init(cipher_ctx **iCtx) {
++  cipher_ctx *ctx;
++  *iCtx = sqlite3Malloc(sizeof(cipher_ctx));
++  ctx = *iCtx;
++  if(ctx == NULL) return SQLITE_NOMEM;
++  memset(ctx, 0, sizeof(cipher_ctx)); 
++  ctx->key = sqlite3Malloc(EVP_MAX_KEY_LENGTH);
++  if(ctx->key == NULL) return SQLITE_NOMEM;
++  return SQLITE_OK;
++}
++
++/**
++  * Free and wipe memory associated with a cipher_ctx
++  */
++static void cipher_ctx_free(cipher_ctx **iCtx) {
++  cipher_ctx *ctx = *iCtx;
++  CODEC_TRACE(("cipher_ctx_free: entered iCtx=%d\n", iCtx));
++  codec_free(ctx->key, ctx->key_sz);
++  codec_free(ctx->pass, ctx->pass_sz);
++  codec_free(ctx, sizeof(cipher_ctx)); 
++}
++
++/**
++  * Copy one cipher_ctx to another. For instance, assuming that read_ctx is a 
++  * fully initialized context, you could copy it to write_ctx and all yet data
++  * and pass information across
++  *
++  * returns SQLITE_OK if initialization was successful
++  * returns SQLITE_NOMEM if an error occured allocating memory
++  */
++static int cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
++  void *key = target->key; 
++  CODEC_TRACE(("cipher_ctx_copy: entered target=%d, source=%d\n", target, source));
++  codec_free(target->pass, target->pass_sz); 
++  memcpy(target, source, sizeof(cipher_ctx));
++  
++  target->key = key; //restore pointer to previously allocated key data
++  memcpy(target->key, source->key, EVP_MAX_KEY_LENGTH);
++  target->pass = sqlite3Malloc(source->pass_sz);
++  if(target->pass == NULL) return SQLITE_NOMEM;
++  memcpy(target->pass, source->pass, source->pass_sz);
++  return SQLITE_OK;
++}
++
++/**
++  * Compare one cipher_ctx to another.
++  *
++  * returns 0 if all the parameters (except the derived key data) are the same
++  * returns 1 otherwise
++  */
++static int cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
++  CODEC_TRACE(("cipher_ctx_cmp: entered c1=%d c2=%d\n", c1, c2));
++
++  if(
++    c1->evp_cipher == c2->evp_cipher
++    && c1->iv_sz == c2->iv_sz
++    && c1->kdf_iter == c2->kdf_iter
++    && c1->key_sz == c2->key_sz
++    && c1->pass_sz == c2->pass_sz
++    && (
++      c1->pass == c2->pass
++      || !memcmp(c1->pass, c2->pass, c1->pass_sz)
++    ) 
++  ) return 0;
++  return 1;
++}
++
++/**
++  * Free and wipe memory associated with a cipher_ctx, including the allocated
++  * read_ctx and write_ctx.
++  */
++static void codec_ctx_free(codec_ctx **iCtx) {
++  codec_ctx *ctx = *iCtx;
++  CODEC_TRACE(("codec_ctx_free: entered iCtx=%d\n", iCtx));
++  codec_free(ctx->kdf_salt, ctx->kdf_salt_sz);
++  codec_free(ctx->buffer, 0);
++  cipher_ctx_free(&ctx->read_ctx);
++  cipher_ctx_free(&ctx->write_ctx);
++  codec_free(ctx, sizeof(codec_ctx)); 
++}
++
++/**
++  * Derive an encryption key for a cipher contex key based on the raw password.
++  *
++  * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill
++  * the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly. 
++  * 
++  * Otherwise, a key data will be derived using PBKDF2
++  * 
++  * returns SQLITE_OK if initialization was successful
++  * returns SQLITE_NOMEM if the key could't be derived (for instance if pass is NULL or pass_sz is 0)
++  */
++static int codec_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { 
++  CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d c_ctx->key_sz=%d\n", 
++    c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, c_ctx->key_sz));
++
++  if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null
++    if (c_ctx->pass_sz == ((c_ctx->key_sz*2)+3) && sqlite3StrNICmp(c_ctx->pass ,"x'", 2) == 0) { 
++      int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */
++      const char *z = c_ctx->pass + 2; /* adjust lead offset of x' */ 
++      CODEC_TRACE(("codec_key_derive: deriving key from hex\n")); 
++      cipher_hex2bin(z, n, c_ctx->key);
++    } else { 
++      CODEC_TRACE(("codec_key_derive: deriving key using PBKDF2\n")); 
++      PKCS5_PBKDF2_HMAC_SHA1(c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->key);
++    }
++    return SQLITE_OK;
++  };
++  return SQLITE_ERROR;
++}
++
++/*
++ * ctx - codec context
++ * pgno - page number in database
++ * size - size in bytes of input and output buffers
++ * mode - 1 to encrypt, 0 to decrypt
++ * in - pointer to input bytes
++ * out - pouter to output bytes
++ */
++static int codec_cipher(cipher_ctx *ctx, Pgno pgno, int mode, int size, unsigned char *in, unsigned char *out) {
++  EVP_CIPHER_CTX ectx;
++  unsigned char *iv;
++  int tmp_csz, csz;
++
++  CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size));
++
++  /* just copy raw data from in to out when key size is 0
++   * i.e. during a rekey of a plaintext database */ 
++  if(ctx->key_sz == 0) {
++    memcpy(out, in, size);
++    return SQLITE_OK;
++  } 
++
++  // FIXME - only run if using an IV
++  size = size - ctx->iv_sz; /* adjust size to useable size and memset reserve at end of page */
++  iv = out + size;
++  if(mode == CIPHER_ENCRYPT) {
++    RAND_pseudo_bytes(iv, ctx->iv_sz);
++  } else {
++    memcpy(iv, in+size, ctx->iv_sz);
++  } 
++  
++  EVP_CipherInit(&ectx, ctx->evp_cipher, NULL, NULL, mode);
++  EVP_CIPHER_CTX_set_padding(&ectx, 0);
++  EVP_CipherInit(&ectx, NULL, ctx->key, iv, mode);
++  EVP_CipherUpdate(&ectx, out, &tmp_csz, in, size);
++  csz = tmp_csz;  
++  out += tmp_csz;
++  EVP_CipherFinal(&ectx, out, &tmp_csz);
++  csz += tmp_csz;
++  EVP_CIPHER_CTX_cleanup(&ectx);
++  assert(size == csz);
++
++  return SQLITE_OK;
++}
++
++int codec_set_kdf_iter(sqlite3* db, int nDb, int kdf_iter, int for_ctx) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("codec_set_kdf_iter: entered db=%d nDb=%d kdf_iter=%d for_ctx=%d\n", db, nDb, kdf_iter, for_ctx));
++
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    cipher_ctx *c_ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++    c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
++
++    c_ctx->kdf_iter = kdf_iter;
++    c_ctx->derive_key = 1;
++
++    if(for_ctx == 2) cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx); 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++/**
++  * 
++  * when for_ctx == 0 then it will change for read
++  * when for_ctx == 1 then it will change for write
++  * when for_ctx == 2 then it will change for both
++  */
++int codec_set_cipher_name(sqlite3* db, int nDb, const char *cipher_name, int for_ctx) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("codec_set_cipher_name: entered db=%d nDb=%d cipher_name=%s for_ctx=%d\n", db, nDb, cipher_name, for_ctx));
++
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    cipher_ctx *c_ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++    c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
++
++    c_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name);
++    c_ctx->key_sz = EVP_CIPHER_key_length(c_ctx->evp_cipher);
++    c_ctx->iv_sz = EVP_CIPHER_iv_length(c_ctx->evp_cipher);
++    c_ctx->derive_key = 1;
++
++    if(for_ctx == 2) cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx); 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("codec_set_pass_key: entered db=%d nDb=%d cipher_name=%s nKey=%d for_ctx=%d\n", db, nDb, zKey, nKey, for_ctx));
++  if(pDb->pBt) {
++    codec_ctx *ctx;
++    cipher_ctx *c_ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++    c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
++  
++    cipher_ctx_set_pass(c_ctx, zKey, nKey);
++    c_ctx->derive_key = 1;
++
++    if(for_ctx == 2) cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx); 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++} 
++
++/*
++ * sqlite3Codec can be called in multiple modes.
++ * encrypt mode - expected to return a pointer to the 
++ *   encrypted data without altering pData.
++ * decrypt mode - expected to return a pointer to pData, with
++ *   the data decrypted in the input buffer
++ */
++void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
++  codec_ctx *ctx = (codec_ctx *) iCtx;
++  int pg_sz = sqlite3BtreeGetPageSize(ctx->pBt);
++  int offset = 0;
++  unsigned char *pData = (unsigned char *) data;
++ 
++  CODEC_TRACE(("sqlite3Codec: entered pgno=%d, mode=%d, ctx->mode_rekey=%d, pg_sz=%d\n", pgno, mode, ctx->mode_rekey, pg_sz));
++
++  /* derive key on first use if necessary */
++  if(ctx->read_ctx->derive_key) {
++    codec_key_derive(ctx, ctx->read_ctx);
++    ctx->read_ctx->derive_key = 0;
++  }
++
++  if(ctx->write_ctx->derive_key) {
++    if(cipher_ctx_cmp(ctx->write_ctx, ctx->read_ctx) == 0) {
++      cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx); // the relevant parameters are the same, just copy read key
++    } else {
++      codec_key_derive(ctx, ctx->write_ctx);
++      ctx->write_ctx->derive_key = 0;
++    }
++  }
++
++
++  if(pgno == 1) offset = FILE_HEADER_SZ; /* adjust starting pointers in data page for header offset on first page*/
++
++  CODEC_TRACE(("sqlite3Codec: switch mode=%d offset=%d\n",  mode, offset));
++  switch(mode) {
++    case 0: /* decrypt */
++    case 2:
++    case 3:
++      if(pgno == 1) memcpy(ctx->buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ); /* copy file header to the first 16 bytes of the page */ 
++      codec_cipher(ctx->read_ctx, pgno, CIPHER_DECRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      memcpy(pData, ctx->buffer, pg_sz); /* copy buffer data back to pData and return */
++      return pData;
++      break;
++    case 6: /* encrypt */
++      if(pgno == 1) memcpy(ctx->buffer, ctx->kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
++      codec_cipher(ctx->write_ctx, pgno, CIPHER_ENCRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      return ctx->buffer; /* return persistent buffer data, pData remains intact */
++      break;
++    case 7:
++      if(pgno == 1) memcpy(ctx->buffer, ctx->kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
++      codec_cipher(ctx->read_ctx, pgno, CIPHER_ENCRYPT, pg_sz - offset, pData + offset, ctx->buffer + offset);
++      return ctx->buffer; /* return persistent buffer data, pData remains intact */
++      break;
++    default:
++      return pData;
++      break;
++  }
++}
++
++
++SQLITE_PRIVATE int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) {
++  struct Db *pDb = &db->aDb[nDb];
++
++  CODEC_TRACE(("sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, zKey, nKey));
++  activate_openssl();
++  
++  if(nKey && zKey && pDb->pBt) {
++    codec_ctx *ctx;
++    int rc;
++    Pager *pPager = pDb->pBt->pBt->pPager;
++    sqlite3_file *fd;
++
++    ctx = sqlite3Malloc(sizeof(codec_ctx));
++    if(ctx == NULL) return SQLITE_NOMEM;
++    memset(ctx, 0, sizeof(codec_ctx)); /* initialize all pointers and values to 0 */
++
++    ctx->pBt = pDb->pBt; /* assign pointer to database btree structure */
++
++    if((rc = cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc; 
++    if((rc = cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc; 
++    
++    /* pre-allocate a page buffer of PageSize bytes. This will
++       be used as a persistent buffer for encryption and decryption 
++       operations to avoid overhead of multiple memory allocations*/
++    ctx->buffer = sqlite3Malloc(sqlite3BtreeGetPageSize(ctx->pBt));
++    if(ctx->buffer == NULL) return SQLITE_NOMEM;
++     
++    /* allocate space for salt data. Then read the first 16 bytes 
++       directly off the database file. This is the salt for the
++       key derivation function. If we get a short read allocate
++       a new random salt value */
++    ctx->kdf_salt_sz = FILE_HEADER_SZ;
++    ctx->kdf_salt = sqlite3Malloc(ctx->kdf_salt_sz);
++    if(ctx->kdf_salt == NULL) return SQLITE_NOMEM;
++
++    fd = sqlite3Pager_get_fd(pPager);
++    if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) {
++      /* if unable to read the bytes, generate random salt */
++      RAND_pseudo_bytes(ctx->kdf_salt, FILE_HEADER_SZ);
++    }
++
++    sqlite3pager_sqlite3PagerSetCodec(sqlite3BtreePager(pDb->pBt), sqlite3Codec, NULL, sqlite3FreeCodecArg, (void *) ctx);
++
++    codec_set_cipher_name(db, nDb, CIPHER, 0);
++    codec_set_kdf_iter(db, nDb, PBKDF2_ITER, 0);
++    codec_set_pass_key(db, nDb, zKey, nKey, 0);
++    cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx);
++    
++    sqlite3BtreeSetPageSize(ctx->pBt, sqlite3BtreeGetPageSize(ctx->pBt), EVP_MAX_IV_LENGTH, 0);
++  }
++  return SQLITE_OK;
++}
++
++SQLITE_PRIVATE void sqlite3FreeCodecArg(void *pCodecArg) {
++  codec_ctx *ctx = (codec_ctx *) pCodecArg;
++  if(pCodecArg == NULL) return;
++  codec_ctx_free(&ctx); // wipe and free allocated memory for the context 
++}
++
++SQLITE_API void sqlite3_activate_see(const char* in) {
++  /* do nothing, security enhancements are always active */
++}
++
++SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
++  CODEC_TRACE(("sqlite3_key: entered db=%d pKey=%s nKey=%d\n", db, pKey, nKey));
++  /* attach key if db and pKey are not null and nKey is > 0 */
++  if(db && pKey && nKey) {
++    sqlite3CodecAttach(db, 0, pKey, nKey); // operate only on the main db 
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++/* sqlite3_rekey 
++** Given a database, this will reencrypt the database using a new key.
++** There are two possible modes of operation. The first is rekeying
++** an existing database that was not previously encrypted. The second
++** is to change the key on an existing database.
++** 
++** The proposed logic for this function follows:
++** 1. Determine if there is already a key present
++** 2. If there is NOT already a key present, create one and attach a codec (key would be null)
++** 3. Initialize a ctx->rekey parameter of the codec
++** 
++** Note: this will require modifications to the sqlite3Codec to support rekey
++**
++*/
++SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
++  CODEC_TRACE(("sqlite3_rekey: entered db=%d pKey=%s, nKey=%d\n", db, pKey, nKey));
++  activate_openssl();
++  if(db && pKey && nKey) {
++    struct Db *pDb = &db->aDb[0];
++    CODEC_TRACE(("sqlite3_rekey: database pDb=%d\n", pDb));
++    if(pDb->pBt) {
++      codec_ctx *ctx;
++      int rc, page_count;
++      Pgno pgno;
++      PgHdr *page;
++      Pager *pPager = pDb->pBt->pBt->pPager;
++
++      sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++     
++      if(ctx == NULL) { 
++        CODEC_TRACE(("sqlite3_rekey: no codec attached to db, attaching now\n"));
++        /* there was no codec attached to this database,so attach one now with a null password */
++        sqlite3CodecAttach(db, 0, pKey, nKey);
++        sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++        
++        /* prepare this setup as if it had already been initialized */
++        RAND_pseudo_bytes(ctx->kdf_salt, ctx->kdf_salt_sz);
++        ctx->read_ctx->key_sz = ctx->read_ctx->iv_sz =  ctx->read_ctx->pass_sz = 0;
++      }
++
++      if(ctx->read_ctx->iv_sz != ctx->write_ctx->iv_sz) {
++        char *error;
++        CODEC_TRACE(("sqlite3_rekey: updating page size for iv_sz change from %d to %d\n", ctx->read_ctx->iv_sz, ctx->write_ctx->iv_sz));
++        db->nextPagesize = sqlite3BtreeGetPageSize(pDb->pBt);
++        pDb->pBt->pBt->pageSizeFixed = 0; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */
++        sqlite3BtreeSetPageSize(pDb->pBt, db->nextPagesize, EVP_MAX_IV_LENGTH, 0);
++        sqlite3RunVacuum(&error, db);
++      }
++
++      codec_set_pass_key(db, 0, pKey, nKey, 1);
++      ctx->mode_rekey = 1; 
++    
++      /* do stuff here to rewrite the database 
++      ** 1. Create a transaction on the database
++      ** 2. Iterate through each page, reading it and then writing it.
++      ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
++      **    note: don't deallocate rekey since it may be used in a subsequent iteration 
++      */
++      rc = sqlite3BtreeBeginTrans(pDb->pBt, 1); /* begin write transaction */
++      sqlite3PagerPagecount(pPager, &page_count);
++      for(pgno = 1; rc == SQLITE_OK && pgno <= page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
++        if(!sqlite3pager_is_mj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
++          rc = sqlite3PagerGet(pPager, pgno, &page);
++          if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
++            rc = sqlite3PagerWrite(page);
++            //printf("sqlite3PagerWrite(%d)\n", pgno);
++            if(rc == SQLITE_OK) {
++              sqlite3PagerUnref(page);
++            } 
++          } 
++        } 
++      }
++
++      /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
++      if(rc == SQLITE_OK) { 
++        CODEC_TRACE(("sqlite3_rekey: committing\n"));
++        db->nextPagesize = sqlite3BtreeGetPageSize(pDb->pBt);
++        rc = sqlite3BtreeCommit(pDb->pBt); 
++        cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx);
++      } else {
++        CODEC_TRACE(("sqlite3_rekey: rollback\n"));
++        sqlite3BtreeRollback(pDb->pBt);
++      }
++
++      ctx->mode_rekey = 0;
++    }
++    return SQLITE_OK;
++  }
++  return SQLITE_ERROR;
++}
++
++SQLITE_PRIVATE void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) {
++  struct Db *pDb = &db->aDb[nDb];
++  CODEC_TRACE(("sqlite3CodecGetKey: entered db=%d, nDb=%d\n", db, nDb));
++  
++  if( pDb->pBt ) {
++    codec_ctx *ctx;
++    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
++
++    if(ctx) { /* if the codec has an attached codec_context user the raw key data */
++      *zKey = ctx->read_ctx->pass;
++      *nKey = ctx->read_ctx->pass_sz;
++    } else {
++      *zKey = NULL;
++      *nKey = 0;
++    }
++  }
++}
++
++
++/* END CRYPTO */
++#endif
++
++/************** End of crypto.c **********************************************/
+ /************** Begin file global.c ******************************************/
+ /*
+ ** 2008 June 13
+@@ -40807,11 +42121,40 @@
+   CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+   return aData;
+ }
+-#endif /* SQLITE_HAS_CODEC */
++#endif /* SQLITE_HAS_CODEC */
++
++#endif /* !SQLITE_OMIT_WAL */
++
++#endif /* SQLITE_OMIT_DISKIO */
++
++/* BEGIN CRYPTO */
++#ifdef SQLITE_HAS_CODEC
++SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx) {
++  *ctx = pPager->pCodec;
++}
++
++SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno) {
++  return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
++}
+ 
+-#endif /* !SQLITE_OMIT_WAL */
++SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager) {
++  return (isOpen(pPager->fd)) ? pPager->fd : NULL;
++}
++
++SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
++  Pager *pPager,
++  void *(*xCodec)(void*,void*,Pgno,int),
++  void (*xCodecSizeChng)(void*,int,int),
++  void (*xCodecFree)(void*),
++  void *pCodec
++){
++  sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec); 
++}
++
++
++#endif
++/* END CRYPTO */
+ 
+-#endif /* SQLITE_OMIT_DISKIO */
+ 
+ /************** End of pager.c ***********************************************/
+ /************** Begin file wal.c *********************************************/
+@@ -43340,854 +44683,208 @@
+ #if defined(SQLITE_HAS_CODEC)
+       if( (pData = sqlite3PagerCodec(pLast))==0 ) return SQLITE_NOMEM;
+ #else
+-      pData = pLast->pData;
+-#endif
+-      walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
+-      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+-      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+-      if( rc!=SQLITE_OK ){
+-        return rc;
+-      }
+-      iOffset += WAL_FRAME_HDRSIZE;
+-      rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset); 
+-      if( rc!=SQLITE_OK ){
+-        return rc;
+-      }
+-      nLast++;
+-      iOffset += szPage;
+-    }
+-
+-    rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+-  }
+-
+-  /* Append data to the wal-index. It is not necessary to lock the 
+-  ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
+-  ** guarantees that there are no other writers, and no data that may
+-  ** be in use by existing readers is being overwritten.
+-  */
+-  iFrame = pWal->hdr.mxFrame;
+-  for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
+-    iFrame++;
+-    rc = walIndexAppend(pWal, iFrame, p->pgno);
+-  }
+-  while( nLast>0 && rc==SQLITE_OK ){
+-    iFrame++;
+-    nLast--;
+-    rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+-  }
+-
+-  if( rc==SQLITE_OK ){
+-    /* Update the private copy of the header. */
+-    pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+-    testcase( szPage<=32768 );
+-    testcase( szPage>=65536 );
+-    pWal->hdr.mxFrame = iFrame;
+-    if( isCommit ){
+-      pWal->hdr.iChange++;
+-      pWal->hdr.nPage = nTruncate;
+-    }
+-    /* If this is a commit, update the wal-index header too. */
+-    if( isCommit ){
+-      walIndexWriteHdr(pWal);
+-      pWal->iCallback = iFrame;
+-    }
+-  }
+-
+-  WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
+-  return rc;
+-}
+-
+-/* 
+-** This routine is called to implement sqlite3_wal_checkpoint() and
+-** related interfaces.
+-**
+-** Obtain a CHECKPOINT lock and then backfill as much information as
+-** we can from WAL into the database.
+-*/
+-SQLITE_PRIVATE int sqlite3WalCheckpoint(
+-  Wal *pWal,                      /* Wal connection */
+-  int sync_flags,                 /* Flags to sync db file with (or 0) */
+-  int nBuf,                       /* Size of temporary buffer */
+-  u8 *zBuf                        /* Temporary buffer to use */
+-){
+-  int rc;                         /* Return code */
+-  int isChanged = 0;              /* True if a new wal-index header is loaded */
+-
+-  assert( pWal->ckptLock==0 );
+-
+-  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+-  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+-  if( rc ){
+-    /* Usually this is SQLITE_BUSY meaning that another thread or process
+-    ** is already running a checkpoint, or maybe a recovery.  But it might
+-    ** also be SQLITE_IOERR. */
+-    return rc;
+-  }
+-  pWal->ckptLock = 1;
+-
+-  /* Copy data from the log to the database file. */
+-  rc = walIndexReadHdr(pWal, &isChanged);
+-  if( rc==SQLITE_OK ){
+-    rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
+-  }
+-  if( isChanged ){
+-    /* If a new wal-index header was loaded before the checkpoint was 
+-    ** performed, then the pager-cache associated with pWal is now
+-    ** out of date. So zero the cached wal-index header to ensure that
+-    ** next time the pager opens a snapshot on this database it knows that
+-    ** the cache needs to be reset.
+-    */
+-    memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+-  }
+-
+-  /* Release the locks. */
+-  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+-  pWal->ckptLock = 0;
+-  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+-  return rc;
+-}
+-
+-/* Return the value to pass to a sqlite3_wal_hook callback, the
+-** number of frames in the WAL at the point of the last commit since
+-** sqlite3WalCallback() was called.  If no commits have occurred since
+-** the last call, then return 0.
+-*/
+-SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
+-  u32 ret = 0;
+-  if( pWal ){
+-    ret = pWal->iCallback;
+-    pWal->iCallback = 0;
+-  }
+-  return (int)ret;
+-}
+-
+-/*
+-** This function is called to change the WAL subsystem into or out
+-** of locking_mode=EXCLUSIVE.
+-**
+-** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
+-** into locking_mode=NORMAL.  This means that we must acquire a lock
+-** on the pWal->readLock byte.  If the WAL is already in locking_mode=NORMAL
+-** or if the acquisition of the lock fails, then return 0.  If the
+-** transition out of exclusive-mode is successful, return 1.  This
+-** operation must occur while the pager is still holding the exclusive
+-** lock on the main database file.
+-**
+-** If op is one, then change from locking_mode=NORMAL into 
+-** locking_mode=EXCLUSIVE.  This means that the pWal->readLock must
+-** be released.  Return 1 if the transition is made and 0 if the
+-** WAL is already in exclusive-locking mode - meaning that this
+-** routine is a no-op.  The pager must already hold the exclusive lock
+-** on the main database file before invoking this operation.
+-**
+-** If op is negative, then do a dry-run of the op==1 case but do
+-** not actually change anything.  The pager uses this to see if it
+-** should acquire the database exclusive lock prior to invoking
+-** the op==1 case.
+-*/
+-SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
+-  int rc;
+-  assert( pWal->writeLock==0 );
+-
+-  /* pWal->readLock is usually set, but might be -1 if there was a 
+-  ** prior error while attempting to acquire are read-lock. This cannot 
+-  ** happen if the connection is actually in exclusive mode (as no xShmLock
+-  ** locks are taken in this case). Nor should the pager attempt to
+-  ** upgrade to exclusive-mode following such an error.
+-  */
+-  assert( pWal->readLock>=0 || pWal->lockError );
+-  assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+-
+-  if( op==0 ){
+-    if( pWal->exclusiveMode ){
+-      pWal->exclusiveMode = 0;
+-      if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+-        pWal->exclusiveMode = 1;
+-      }
+-      rc = pWal->exclusiveMode==0;
+-    }else{
+-      /* Already in locking_mode=NORMAL */
+-      rc = 0;
+-    }
+-  }else if( op>0 ){
+-    assert( pWal->exclusiveMode==0 );
+-    assert( pWal->readLock>=0 );
+-    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+-    pWal->exclusiveMode = 1;
+-    rc = 1;
+-  }else{
+-    rc = pWal->exclusiveMode==0;
+-  }
+-  return rc;
+-}
+-
+-#endif /* #ifndef SQLITE_OMIT_WAL */
+-
+-/************** End of wal.c *************************************************/
+-/************** Begin file btmutex.c *****************************************/
+-/*
+-** 2007 August 27
+-**
+-** The author disclaims copyright to this source code.  In place of
+-** a legal notice, here is a blessing:
+-**
+-**    May you do good and not evil.
+-**    May you find forgiveness for yourself and forgive others.
+-**    May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-**
+-** This file contains code used to implement mutexes on Btree objects.
+-** This code really belongs in btree.c.  But btree.c is getting too
+-** big and we want to break it down some.  This packaged seemed like
+-** a good breakout.
+-*/
+-/************** Include btreeInt.h in the middle of btmutex.c ****************/
+-/************** Begin file btreeInt.h ****************************************/
+-/*
+-** 2004 April 6
+-**
+-** The author disclaims copyright to this source code.  In place of
+-** a legal notice, here is a blessing:
+-**
+-**    May you do good and not evil.
+-**    May you find forgiveness for yourself and forgive others.
+-**    May you share freely, never taking more than you give.
+-**
+-*************************************************************************
+-** This file implements a external (disk-based) database using BTrees.
+-** For a detailed discussion of BTrees, refer to
+-**
+-**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
+-**     "Sorting And Searching", pages 473-480. Addison-Wesley
+-**     Publishing Company, Reading, Massachusetts.
+-**
+-** The basic idea is that each page of the file contains N database
+-** entries and N+1 pointers to subpages.
+-**
+-**   ----------------------------------------------------------------
+-**   |  Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
+-**   ----------------------------------------------------------------
+-**
+-** All of the keys on the page that Ptr(0) points to have values less
+-** than Key(0).  All of the keys on page Ptr(1) and its subpages have
+-** values greater than Key(0) and less than Key(1).  All of the keys
+-** on Ptr(N) and its subpages have values greater than Key(N-1).  And
+-** so forth.
+-**
+-** Finding a particular key requires reading O(log(M)) pages from the 
+-** disk where M is the number of entries in the tree.
+-**
+-** In this implementation, a single file can hold one or more separate 
+-** BTrees.  Each BTree is identified by the index of its root page.  The
+-** key and data for any entry are combined to form the "payload".  A
+-** fixed amount of payload can be carried directly on the database
+-** page.  If the payload is larger than the preset amount then surplus
+-** bytes are stored on overflow pages.  The payload for an entry
+-** and the preceding pointer are combined to form a "Cell".  Each 
+-** page has a small header which contains the Ptr(N) pointer and other
+-** information such as the size of key and data.
+-**
+-** FORMAT DETAILS
+-**
+-** The file is divided into pages.  The first page is called page 1,
+-** the second is page 2, and so forth.  A page number of zero indicates
+-** "no such page".  The page size can be any power of 2 between 512 and 65536.
+-** Each page can be either a btree page, a freelist page, an overflow
+-** page, or a pointer-map page.
+-**
+-** The first page is always a btree page.  The first 100 bytes of the first
+-** page contain a special header (the "file header") that describes the file.
+-** The format of the file header is as follows:
+-**
+-**   OFFSET   SIZE    DESCRIPTION
+-**      0      16     Header string: "SQLite format 3\000"
+-**     16       2     Page size in bytes.  
+-**     18       1     File format write version
+-**     19       1     File format read version
+-**     20       1     Bytes of unused space at the end of each page
+-**     21       1     Max embedded payload fraction
+-**     22       1     Min embedded payload fraction
+-**     23       1     Min leaf payload fraction
+-**     24       4     File change counter
+-**     28       4     Reserved for future use
+-**     32       4     First freelist page
+-**     36       4     Number of freelist pages in the file
+-**     40      60     15 4-byte meta values passed to higher layers
+-**
+-**     40       4     Schema cookie
+-**     44       4     File format of schema layer
+-**     48       4     Size of page cache
+-**     52       4     Largest root-page (auto/incr_vacuum)
+-**     56       4     1=UTF-8 2=UTF16le 3=UTF16be
+-**     60       4     User version
+-**     64       4     Incremental vacuum mode
+-**     68       4     unused
+-**     72       4     unused
+-**     76       4     unused
+-**
+-** All of the integer values are big-endian (most significant byte first).
+-**
+-** The file change counter is incremented when the database is changed
+-** This counter allows other processes to know when the file has changed
+-** and thus when they need to flush their cache.
+-**
+-** The max embedded payload fraction is the amount of the total usable
+-** space in a page that can be consumed by a single cell for standard
+-** B-tree (non-LEAFDATA) tables.  A value of 255 means 100%.  The default
+-** is to limit the maximum cell size so that at least 4 cells will fit
+-** on one page.  Thus the default max embedded payload fraction is 64.
+-**
+-** If the payload for a cell is larger than the max payload, then extra
+-** payload is spilled to overflow pages.  Once an overflow page is allocated,
+-** as many bytes as possible are moved into the overflow pages without letting
+-** the cell size drop below the min embedded payload fraction.
+-**
+-** The min leaf payload fraction is like the min embedded payload fraction
+-** except that it applies to leaf nodes in a LEAFDATA tree.  The maximum
+-** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
+-** not specified in the header.
+-**
+-** Each btree pages is divided into three sections:  The header, the
+-** cell pointer array, and the cell content area.  Page 1 also has a 100-byte
+-** file header that occurs before the page header.
+-**
+-**      |----------------|
+-**      | file header    |   100 bytes.  Page 1 only.
+-**      |----------------|
+-**      | page header    |   8 bytes for leaves.  12 bytes for interior nodes
+-**      |----------------|
+-**      | cell pointer   |   |  2 bytes per cell.  Sorted order.
+-**      | array          |   |  Grows downward
+-**      |                |   v
+-**      |----------------|
+-**      | unallocated    |
+-**      | space          |
+-**      |----------------|   ^  Grows upwards
+-**      | cell content   |   |  Arbitrary order interspersed with freeblocks.
+-**      | area           |   |  and free space fragments.
+-**      |----------------|
+-**
+-** The page headers looks like this:
+-**
+-**   OFFSET   SIZE     DESCRIPTION
+-**      0       1      Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
+-**      1       2      byte offset to the first freeblock
+-**      3       2      number of cells on this page
+-**      5       2      first byte of the cell content area
+-**      7       1      number of fragmented free bytes
+-**      8       4      Right child (the Ptr(N) value).  Omitted on leaves.
+-**
+-** The flags define the format of this btree page.  The leaf flag means that
+-** this page has no children.  The zerodata flag means that this page carries
+-** only keys and no data.  The intkey flag means that the key is a integer
+-** which is stored in the key size entry of the cell header rather than in
+-** the payload area.
+-**
+-** The cell pointer array begins on the first byte after the page header.
+-** The cell pointer array contains zero or more 2-byte numbers which are
+-** offsets from the beginning of the page to the cell content in the cell
+-** content area.  The cell pointers occur in sorted order.  The system strives
+-** to keep free space after the last cell pointer so that new cells can
+-** be easily added without having to defragment the page.
+-**
+-** Cell content is stored at the very end of the page and grows toward the
+-** beginning of the page.
+-**
+-** Unused space within the cell content area is collected into a linked list of
+-** freeblocks.  Each freeblock is at least 4 bytes in size.  The byte offset
+-** to the first freeblock is given in the header.  Freeblocks occur in
+-** increasing order.  Because a freeblock must be at least 4 bytes in size,
+-** any group of 3 or fewer unused bytes in the cell content area cannot
+-** exist on the freeblock chain.  A group of 3 or fewer free bytes is called
+-** a fragment.  The total number of bytes in all fragments is recorded.
+-** in the page header at offset 7.
+-**
+-**    SIZE    DESCRIPTION
+-**      2     Byte offset of the next freeblock
+-**      2     Bytes in this freeblock
+-**
+-** Cells are of variable length.  Cells are stored in the cell content area at
+-** the end of the page.  Pointers to the cells are in the cell pointer array
+-** that immediately follows the page header.  Cells is not necessarily
+-** contiguous or in order, but cell pointers are contiguous and in order.
+-**
+-** Cell content makes use of variable length integers.  A variable
+-** length integer is 1 to 9 bytes where the lower 7 bits of each 
+-** byte are used.  The integer consists of all bytes that have bit 8 set and
+-** the first byte with bit 8 clear.  The most significant byte of the integer
+-** appears first.  A variable-length integer may not be more than 9 bytes long.
+-** As a special case, all 8 bytes of the 9th byte are used as data.  This
+-** allows a 64-bit integer to be encoded in 9 bytes.
+-**
+-**    0x00                      becomes  0x00000000
+-**    0x7f                      becomes  0x0000007f
+-**    0x81 0x00                 becomes  0x00000080
+-**    0x82 0x00                 becomes  0x00000100
+-**    0x80 0x7f                 becomes  0x0000007f
+-**    0x8a 0x91 0xd1 0xac 0x78  becomes  0x12345678
+-**    0x81 0x81 0x81 0x81 0x01  becomes  0x10204081
+-**
+-** Variable length integers are used for rowids and to hold the number of
+-** bytes of key and data in a btree cell.
+-**
+-** The content of a cell looks like this:
+-**
+-**    SIZE    DESCRIPTION
+-**      4     Page number of the left child. Omitted if leaf flag is set.
+-**     var    Number of bytes of data. Omitted if the zerodata flag is set.
+-**     var    Number of bytes of key. Or the key itself if intkey flag is set.
+-**      *     Payload
+-**      4     First page of the overflow chain.  Omitted if no overflow
+-**
+-** Overflow pages form a linked list.  Each page except the last is completely
+-** filled with data (pagesize - 4 bytes).  The last page can have as little
+-** as 1 byte of data.
+-**
+-**    SIZE    DESCRIPTION
+-**      4     Page number of next overflow page
+-**      *     Data
+-**
+-** Freelist pages come in two subtypes: trunk pages and leaf pages.  The
+-** file header points to the first in a linked list of trunk page.  Each trunk
+-** page points to multiple leaf pages.  The content of a leaf page is
+-** unspecified.  A trunk page looks like this:
+-**
+-**    SIZE    DESCRIPTION
+-**      4     Page number of next trunk page
+-**      4     Number of leaf pointers on this page
+-**      *     zero or more pages numbers of leaves
+-*/
+-
+-
+-/* The following value is the maximum cell size assuming a maximum page
+-** size give above.
+-*/
+-#define MX_CELL_SIZE(pBt)  (pBt->pageSize-8)
+-
+-/* The maximum number of cells on a single page of the database.  This
+-** assumes a minimum cell size of 6 bytes  (4 bytes for the cell itself
+-** plus 2 bytes for the index to the cell in the page header).  Such
+-** small cells will be rare, but they are possible.
+-*/
+-#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
+-
+-/* Forward declarations */
+-typedef struct MemPage MemPage;
+-typedef struct BtLock BtLock;
+-
+-/*
+-** This is a magic string that appears at the beginning of every
+-** SQLite database in order to identify the file as a real database.
+-**
+-** You can change this value at compile-time by specifying a
+-** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
+-** header must be exactly 16 bytes including the zero-terminator so
+-** the string itself should be 15 characters long.  If you change
+-** the header, then your custom library will not be able to read 
+-** databases generated by the standard tools and the standard tools
+-** will not be able to read databases created by your custom library.
+-*/
+-#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
+-#  define SQLITE_FILE_HEADER "SQLite format 3"
+-#endif
+-
+-/*
+-** Page type flags.  An ORed combination of these flags appear as the
+-** first byte of on-disk image of every BTree page.
+-*/
+-#define PTF_INTKEY    0x01
+-#define PTF_ZERODATA  0x02
+-#define PTF_LEAFDATA  0x04
+-#define PTF_LEAF      0x08
+-
+-/*
+-** As each page of the file is loaded into memory, an instance of the following
+-** structure is appended and initialized to zero.  This structure stores
+-** information about the page that is decoded from the raw file page.
+-**
+-** The pParent field points back to the parent page.  This allows us to
+-** walk up the BTree from any leaf to the root.  Care must be taken to
+-** unref() the parent page pointer when this page is no longer referenced.
+-** The pageDestructor() routine handles that chore.
+-**
+-** Access to all fields of this structure is controlled by the mutex
+-** stored in MemPage.pBt->mutex.
+-*/
+-struct MemPage {
+-  u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
+-  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
+-  u8 intKey;           /* True if intkey flag is set */
+-  u8 leaf;             /* True if leaf flag is set */
+-  u8 hasData;          /* True if this page stores data */
+-  u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
+-  u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
+-  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
+-  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
+-  u16 cellOffset;      /* Index in aData of first cell pointer */
+-  u16 nFree;           /* Number of free bytes on the page */
+-  u16 nCell;           /* Number of cells on this page, local and ovfl */
+-  u16 maskPage;        /* Mask for page offset */
+-  struct _OvflCell {   /* Cells that will not fit on aData[] */
+-    u8 *pCell;          /* Pointers to the body of the overflow cell */
+-    u16 idx;            /* Insert this cell before idx-th non-overflow cell */
+-  } aOvfl[5];
+-  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
+-  u8 *aData;           /* Pointer to disk image of the page data */
+-  DbPage *pDbPage;     /* Pager page handle */
+-  Pgno pgno;           /* Page number for this page */
+-};
++      pData = pLast->pData;
++#endif
++      walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
++      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
++      rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
++      if( rc!=SQLITE_OK ){
++        return rc;
++      }
++      iOffset += WAL_FRAME_HDRSIZE;
++      rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset); 
++      if( rc!=SQLITE_OK ){
++        return rc;
++      }
++      nLast++;
++      iOffset += szPage;
++    }
+ 
+-/*
+-** The in-memory image of a disk page has the auxiliary information appended
+-** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
+-** that extra information.
+-*/
+-#define EXTRA_SIZE sizeof(MemPage)
++    rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
++  }
+ 
+-/*
+-** A linked list of the following structures is stored at BtShared.pLock.
+-** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
+-** is opened on the table with root page BtShared.iTable. Locks are removed
+-** from this list when a transaction is committed or rolled back, or when
+-** a btree handle is closed.
+-*/
+-struct BtLock {
+-  Btree *pBtree;        /* Btree handle holding this lock */
+-  Pgno iTable;          /* Root page of table */
+-  u8 eLock;             /* READ_LOCK or WRITE_LOCK */
+-  BtLock *pNext;        /* Next in BtShared.pLock list */
+-};
++  /* Append data to the wal-index. It is not necessary to lock the 
++  ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
++  ** guarantees that there are no other writers, and no data that may
++  ** be in use by existing readers is being overwritten.
++  */
++  iFrame = pWal->hdr.mxFrame;
++  for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
++    iFrame++;
++    rc = walIndexAppend(pWal, iFrame, p->pgno);
++  }
++  while( nLast>0 && rc==SQLITE_OK ){
++    iFrame++;
++    nLast--;
++    rc = walIndexAppend(pWal, iFrame, pLast->pgno);
++  }
+ 
+-/* Candidate values for BtLock.eLock */
+-#define READ_LOCK     1
+-#define WRITE_LOCK    2
++  if( rc==SQLITE_OK ){
++    /* Update the private copy of the header. */
++    pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
++    testcase( szPage<=32768 );
++    testcase( szPage>=65536 );
++    pWal->hdr.mxFrame = iFrame;
++    if( isCommit ){
++      pWal->hdr.iChange++;
++      pWal->hdr.nPage = nTruncate;
++    }
++    /* If this is a commit, update the wal-index header too. */
++    if( isCommit ){
++      walIndexWriteHdr(pWal);
++      pWal->iCallback = iFrame;
++    }
++  }
+ 
+-/* A Btree handle
+-**
+-** A database connection contains a pointer to an instance of
+-** this object for every database file that it has open.  This structure
+-** is opaque to the database connection.  The database connection cannot
+-** see the internals of this structure and only deals with pointers to
+-** this structure.
+-**
+-** For some database files, the same underlying database cache might be 
+-** shared between multiple connections.  In that case, each connection
+-** has it own instance of this object.  But each instance of this object
+-** points to the same BtShared object.  The database cache and the
+-** schema associated with the database file are all contained within
+-** the BtShared object.
+-**
+-** All fields in this structure are accessed under sqlite3.mutex.
+-** The pBt pointer itself may not be changed while there exists cursors 
+-** in the referenced BtShared that point back to this Btree since those
+-** cursors have to do go through this Btree to find their BtShared and
+-** they often do so without holding sqlite3.mutex.
+-*/
+-struct Btree {
+-  sqlite3 *db;       /* The database connection holding this btree */
+-  BtShared *pBt;     /* Sharable content of this btree */
+-  u8 inTrans;        /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+-  u8 sharable;       /* True if we can share pBt with another db */
+-  u8 locked;         /* True if db currently has pBt locked */
+-  int wantToLock;    /* Number of nested calls to sqlite3BtreeEnter() */
+-  int nBackup;       /* Number of backup operations reading this btree */
+-  Btree *pNext;      /* List of other sharable Btrees from the same db */
+-  Btree *pPrev;      /* Back pointer of the same list */
+-#ifndef SQLITE_OMIT_SHARED_CACHE
+-  BtLock lock;       /* Object used to lock page 1 */
+-#endif
+-};
++  WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
++  return rc;
++}
+ 
+-/*
+-** Btree.inTrans may take one of the following values.
++/* 
++** This routine is called to implement sqlite3_wal_checkpoint() and
++** related interfaces.
+ **
+-** If the shared-data extension is enabled, there may be multiple users
+-** of the Btree structure. At most one of these may open a write transaction,
+-** but any number may have active read transactions.
++** Obtain a CHECKPOINT lock and then backfill as much information as
++** we can from WAL into the database.
+ */
+-#define TRANS_NONE  0
+-#define TRANS_READ  1
+-#define TRANS_WRITE 2
++SQLITE_PRIVATE int sqlite3WalCheckpoint(
++  Wal *pWal,                      /* Wal connection */
++  int sync_flags,                 /* Flags to sync db file with (or 0) */
++  int nBuf,                       /* Size of temporary buffer */
++  u8 *zBuf                        /* Temporary buffer to use */
++){
++  int rc;                         /* Return code */
++  int isChanged = 0;              /* True if a new wal-index header is loaded */
+ 
+-/*
+-** An instance of this object represents a single database file.
+-** 
+-** A single database file can be in use as the same time by two
+-** or more database connections.  When two or more connections are
+-** sharing the same database file, each connection has it own
+-** private Btree object for the file and each of those Btrees points
+-** to this one BtShared object.  BtShared.nRef is the number of
+-** connections currently sharing this database file.
+-**
+-** Fields in this structure are accessed under the BtShared.mutex
+-** mutex, except for nRef and pNext which are accessed under the
+-** global SQLITE_MUTEX_STATIC_MASTER mutex.  The pPager field
+-** may not be modified once it is initially set as long as nRef>0.
+-** The pSchema field may be set once under BtShared.mutex and
+-** thereafter is unchanged as long as nRef>0.
+-**
+-** isPending:
+-**
+-**   If a BtShared client fails to obtain a write-lock on a database
+-**   table (because there exists one or more read-locks on the table),
+-**   the shared-cache enters 'pending-lock' state and isPending is
+-**   set to true.
+-**
+-**   The shared-cache leaves the 'pending lock' state when either of
+-**   the following occur:
+-**
+-**     1) The current writer (BtShared.pWriter) concludes its transaction, OR
+-**     2) The number of locks held by other connections drops to zero.
+-**
+-**   while in the 'pending-lock' state, no connection may start a new
+-**   transaction.
+-**
+-**   This feature is included to help prevent writer-starvation.
+-*/
+-struct BtShared {
+-  Pager *pPager;        /* The page cache */
+-  sqlite3 *db;          /* Database connection currently using this Btree */
+-  BtCursor *pCursor;    /* A list of all open cursors */
+-  MemPage *pPage1;      /* First page of the database */
+-  u8 readOnly;          /* True if the underlying file is readonly */
+-  u8 pageSizeFixed;     /* True if the page size can no longer be changed */
+-  u8 secureDelete;      /* True if secure_delete is enabled */
+-  u8 initiallyEmpty;    /* Database is empty at start of transaction */
+-#ifndef SQLITE_OMIT_AUTOVACUUM
+-  u8 autoVacuum;        /* True if auto-vacuum is enabled */
+-  u8 incrVacuum;        /* True if incr-vacuum is enabled */
+-#endif
+-  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
+-  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
+-  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
+-  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
+-  u8 inTransaction;     /* Transaction state */
+-  u8 doNotUseWAL;       /* If true, do not open write-ahead-log file */
+-  u32 pageSize;         /* Total number of bytes on a page */
+-  u32 usableSize;       /* Number of usable bytes on each page */
+-  int nTransaction;     /* Number of open transactions (read + write) */
+-  u32 nPage;            /* Number of pages in the database */
+-  void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
+-  void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
+-  sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
+-  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
+-#ifndef SQLITE_OMIT_SHARED_CACHE
+-  int nRef;             /* Number of references to this structure */
+-  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
+-  BtLock *pLock;        /* List of locks held on this shared-btree struct */
+-  Btree *pWriter;       /* Btree with currently open write transaction */
+-  u8 isExclusive;       /* True if pWriter has an EXCLUSIVE lock on the db */
+-  u8 isPending;         /* If waiting for read-locks to clear */
+-#endif
+-  u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
+-};
++  assert( pWal->ckptLock==0 );
+ 
+-/*
+-** An instance of the following structure is used to hold information
+-** about a cell.  The parseCellPtr() function fills in this structure
+-** based on information extract from the raw disk page.
+-*/
+-typedef struct CellInfo CellInfo;
+-struct CellInfo {
+-  u8 *pCell;     /* Pointer to the start of cell content */
+-  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
+-  u32 nData;     /* Number of bytes of data */
+-  u32 nPayload;  /* Total amount of payload */
+-  u16 nHeader;   /* Size of the cell content header in bytes */
+-  u16 nLocal;    /* Amount of payload held locally */
+-  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
+-  u16 nSize;     /* Size of the cell content on the main b-tree page */
+-};
++  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
++  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
++  if( rc ){
++    /* Usually this is SQLITE_BUSY meaning that another thread or process
++    ** is already running a checkpoint, or maybe a recovery.  But it might
++    ** also be SQLITE_IOERR. */
++    return rc;
++  }
++  pWal->ckptLock = 1;
+ 
+-/*
+-** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
+-** this will be declared corrupt. This value is calculated based on a
+-** maximum database size of 2^31 pages a minimum fanout of 2 for a
+-** root-node and 3 for all other internal nodes.
+-**
+-** If a tree that appears to be taller than this is encountered, it is
+-** assumed that the database is corrupt.
+-*/
+-#define BTCURSOR_MAX_DEPTH 20
++  /* Copy data from the log to the database file. */
++  rc = walIndexReadHdr(pWal, &isChanged);
++  if( rc==SQLITE_OK ){
++    rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
++  }
++  if( isChanged ){
++    /* If a new wal-index header was loaded before the checkpoint was 
++    ** performed, then the pager-cache associated with pWal is now
++    ** out of date. So zero the cached wal-index header to ensure that
++    ** next time the pager opens a snapshot on this database it knows that
++    ** the cache needs to be reset.
++    */
++    memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
++  }
+ 
+-/*
+-** A cursor is a pointer to a particular entry within a particular
+-** b-tree within a database file.
+-**
+-** The entry is identified by its MemPage and the index in
+-** MemPage.aCell[] of the entry.
+-**
+-** A single database file can shared by two more database connections,
+-** but cursors cannot be shared.  Each cursor is associated with a
+-** particular database connection identified BtCursor.pBtree.db.
+-**
+-** Fields in this structure are accessed under the BtShared.mutex
+-** found at self->pBt->mutex. 
++  /* Release the locks. */
++  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
++  pWal->ckptLock = 0;
++  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
++  return rc;
++}
++
++/* Return the value to pass to a sqlite3_wal_hook callback, the
++** number of frames in the WAL at the point of the last commit since
++** sqlite3WalCallback() was called.  If no commits have occurred since
++** the last call, then return 0.
+ */
+-struct BtCursor {
+-  Btree *pBtree;            /* The Btree to which this cursor belongs */
+-  BtShared *pBt;            /* The BtShared this cursor points to */
+-  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
+-  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
+-  Pgno pgnoRoot;            /* The root page of this tree */
+-  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
+-  CellInfo info;            /* A parse of the cell we are pointing at */
+-  u8 wrFlag;                /* True if writable */
+-  u8 atLast;                /* Cursor pointing to the last entry */
+-  u8 validNKey;             /* True if info.nKey is valid */
+-  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
+-  void *pKey;      /* Saved key that was cursor's last known position */
+-  i64 nKey;        /* Size of pKey, or last integer key */
+-  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
+-#ifndef SQLITE_OMIT_INCRBLOB
+-  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
+-  Pgno *aOverflow;          /* Cache of overflow page locations */
+-#endif
+-  i16 iPage;                            /* Index of current page in apPage */
+-  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
+-  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
+-};
++SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
++  u32 ret = 0;
++  if( pWal ){
++    ret = pWal->iCallback;
++    pWal->iCallback = 0;
++  }
++  return (int)ret;
++}
+ 
+ /*
+-** Potential values for BtCursor.eState.
+-**
+-** CURSOR_VALID:
+-**   Cursor points to a valid entry. getPayload() etc. may be called.
++** This function is called to change the WAL subsystem into or out
++** of locking_mode=EXCLUSIVE.
+ **
+-** CURSOR_INVALID:
+-**   Cursor does not point to a valid entry. This can happen (for example) 
+-**   because the table is empty or because BtreeCursorFirst() has not been
+-**   called.
++** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
++** into locking_mode=NORMAL.  This means that we must acquire a lock
++** on the pWal->readLock byte.  If the WAL is already in locking_mode=NORMAL
++** or if the acquisition of the lock fails, then return 0.  If the
++** transition out of exclusive-mode is successful, return 1.  This
++** operation must occur while the pager is still holding the exclusive
++** lock on the main database file.
+ **
+-** CURSOR_REQUIRESEEK:
+-**   The table that this cursor was opened on still exists, but has been 
+-**   modified since the cursor was last used. The cursor position is saved
+-**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in 
+-**   this state, restoreCursorPosition() can be called to attempt to
+-**   seek the cursor to the saved position.
++** If op is one, then change from locking_mode=NORMAL into 
++** locking_mode=EXCLUSIVE.  This means that the pWal->readLock must
++** be released.  Return 1 if the transition is made and 0 if the
++** WAL is already in exclusive-locking mode - meaning that this
++** routine is a no-op.  The pager must already hold the exclusive lock
++** on the main database file before invoking this operation.
+ **
+-** CURSOR_FAULT:
+-**   A unrecoverable error (an I/O error or a malloc failure) has occurred
+-**   on a different connection that shares the BtShared cache with this
+-**   cursor.  The error has left the cache in an inconsistent state.
+-**   Do nothing else with this cursor.  Any attempt to use the cursor
+-**   should return the error code stored in BtCursor.skip
++** If op is negative, then do a dry-run of the op==1 case but do
++** not actually change anything.  The pager uses this to see if it
++** should acquire the database exclusive lock prior to invoking
++** the op==1 case.
+ */
+-#define CURSOR_INVALID           0
+-#define CURSOR_VALID             1
+-#define CURSOR_REQUIRESEEK       2
+-#define CURSOR_FAULT             3
++SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
++  int rc;
++  assert( pWal->writeLock==0 );
+ 
+-/* 
+-** The database page the PENDING_BYTE occupies. This page is never used.
+-*/
+-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
++  /* pWal->readLock is usually set, but might be -1 if there was a 
++  ** prior error while attempting to acquire are read-lock. This cannot 
++  ** happen if the connection is actually in exclusive mode (as no xShmLock
++  ** locks are taken in this case). Nor should the pager attempt to
++  ** upgrade to exclusive-mode following such an error.
++  */
++  assert( pWal->readLock>=0 || pWal->lockError );
++  assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+ 
+-/*
+-** These macros define the location of the pointer-map entry for a 
+-** database page. The first argument to each is the number of usable
+-** bytes on each page of the database (often 1024). The second is the
+-** page number to look up in the pointer map.
+-**
+-** PTRMAP_PAGENO returns the database page number of the pointer-map
+-** page that stores the required pointer. PTRMAP_PTROFFSET returns
+-** the offset of the requested map entry.
+-**
+-** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
+-** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
+-** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
+-** this test.
+-*/
+-#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
+-#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
+-#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
++  if( op==0 ){
++    if( pWal->exclusiveMode ){
++      pWal->exclusiveMode = 0;
++      if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
++        pWal->exclusiveMode = 1;
++      }
++      rc = pWal->exclusiveMode==0;
++    }else{
++      /* Already in locking_mode=NORMAL */
++      rc = 0;
++    }
++  }else if( op>0 ){
++    assert( pWal->exclusiveMode==0 );
++    assert( pWal->readLock>=0 );
++    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
++    pWal->exclusiveMode = 1;
++    rc = 1;
++  }else{
++    rc = pWal->exclusiveMode==0;
++  }
++  return rc;
++}
++
++#endif /* #ifndef SQLITE_OMIT_WAL */
+ 
++/************** End of wal.c *************************************************/
++/************** Begin file btmutex.c *****************************************/
+ /*
+-** The pointer map is a lookup table that identifies the parent page for
+-** each child page in the database file.  The parent page is the page that
+-** contains a pointer to the child.  Every page in the database contains
+-** 0 or 1 parent pages.  (In this context 'database page' refers
+-** to any page that is not part of the pointer map itself.)  Each pointer map
+-** entry consists of a single byte 'type' and a 4 byte parent page number.
+-** The PTRMAP_XXX identifiers below are the valid types.
+-**
+-** The purpose of the pointer map is to facility moving pages from one
+-** position in the file to another as part of autovacuum.  When a page
+-** is moved, the pointer in its parent must be updated to point to the
+-** new location.  The pointer map is used to locate the parent page quickly.
+-**
+-** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
+-**                  used in this case.
++** 2007 August 27
+ **
+-** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number 
+-**                  is not used in this case.
++** The author disclaims copyright to this source code.  In place of
++** a legal notice, here is a blessing:
+ **
+-** PTRMAP_OVERFLOW1: The database page is the first page in a list of 
+-**                   overflow pages. The page number identifies the page that
+-**                   contains the cell with a pointer to this overflow page.
++**    May you do good and not evil.
++**    May you find forgiveness for yourself and forgive others.
++**    May you share freely, never taking more than you give.
+ **
+-** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
+-**                   overflow pages. The page-number identifies the previous
+-**                   page in the overflow page list.
++*************************************************************************
+ **
+-** PTRMAP_BTREE: The database page is a non-root btree page. The page number
+-**               identifies the parent page in the btree.
+-*/
+-#define PTRMAP_ROOTPAGE 1
+-#define PTRMAP_FREEPAGE 2
+-#define PTRMAP_OVERFLOW1 3
+-#define PTRMAP_OVERFLOW2 4
+-#define PTRMAP_BTREE 5
+-
+-/* A bunch of assert() statements to check the transaction state variables
+-** of handle p (type Btree*) are internally consistent.
+-*/
+-#define btreeIntegrity(p) \
+-  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
+-  assert( p->pBt->inTransaction>=p->inTrans ); 
+-
+-
+-/*
+-** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
+-** if the database supports auto-vacuum or not. Because it is used
+-** within an expression that is an argument to another macro 
+-** (sqliteMallocRaw), it is not possible to use conditional compilation.
+-** So, this macro is defined instead.
+-*/
+-#ifndef SQLITE_OMIT_AUTOVACUUM
+-#define ISAUTOVACUUM (pBt->autoVacuum)
+-#else
+-#define ISAUTOVACUUM 0
+-#endif
+-
+-
+-/*
+-** This structure is passed around through all the sanity checking routines
+-** in order to keep track of some global state information.
+-*/
+-typedef struct IntegrityCk IntegrityCk;
+-struct IntegrityCk {
+-  BtShared *pBt;    /* The tree being checked out */
+-  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
+-  Pgno nPage;       /* Number of pages in the database */
+-  int *anRef;       /* Number of times each page is referenced */
+-  int mxErr;        /* Stop accumulating errors when this reaches zero */
+-  int nErr;         /* Number of messages written to zErrMsg so far */
+-  int mallocFailed; /* A memory allocation error has occurred */
+-  StrAccum errMsg;  /* Accumulate the error message text here */
+-};
+-
+-/*
+-** Read or write a two- and four-byte big-endian integer values.
++** This file contains code used to implement mutexes on Btree objects.
++** This code really belongs in btree.c.  But btree.c is getting too
++** big and we want to break it down some.  This packaged seemed like
++** a good breakout.
+ */
+-#define get2byte(x)   ((x)[0]<<8 | (x)[1])
+-#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
+-#define get4byte sqlite3Get4byte
+-#define put4byte sqlite3Put4byte
+-
+-/************** End of btreeInt.h ********************************************/
+-/************** Continuing where we left off in btmutex.c ********************/
+ #ifndef SQLITE_OMIT_SHARED_CACHE
+ #if SQLITE_THREADSAFE
+ 
+@@ -85120,60 +85817,6 @@
+ 
+ #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
+   /*
+-  **   PRAGMA proc_list
+-  **
+-  ** Return a single row for each procedure, the returned data set are:
+-  **
+-  ** name:         Procedure name
+-  ** is_aggregate: True is procedure is an aggregate
+-  ** nargs:        Number of arguments of the procedure, or -1 if unlimited
+-  ** spe_name:     Specific name (unique procedure name)
+-  */
+-  if( sqlite3StrICmp(zLeft, "proc_list")==0 ){
+-    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+-
+-    sqlite3VdbeSetNumCols(v, 4);
+-    pParse->nMem = 4;
+-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "name", SQLITE_STATIC);
+-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "is_aggregate", SQLITE_STATIC);
+-    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "nargs", SQLITE_STATIC);
+-    sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "spe_name", SQLITE_STATIC);
+-    int j;
+-    for(j=0; j<ArraySize(db->aFunc.a); j++){
+-      FuncDef *func;
+-      for (func =db->aFunc.a[j]; func; func = func->pNext) {
+-	char *sname;
+-	int size;
+-	size = strlen (func->zName) + 25;
+-	sname = sqlite3_malloc (sizeof (char) * size);
+-	snprintf (sname, size-1, "%s_%d_%d", func->zName, func->nArg, func->iPrefEnc);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, func->zName, 0);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->xFinalize ? 1 : 0, 2);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->nArg, 3);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, sname, 0);
+-	sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+-	sqlite3_free (sname);
+-      }
+-    }
+-    for(j=0; j<ArraySize(sqlite3GlobalFunctions.a); j++){
+-      FuncDef *func;
+-      for (func =sqlite3GlobalFunctions.a[j]; func; func = func->pNext) {
+-	char *sname;
+-	int size;
+-	size = strlen (func->zName) + 25;
+-	sname = sqlite3_malloc (sizeof (char) * size);
+-	snprintf (sname, size-1, "%s_%d_%d", func->zName, func->nArg, func->iPrefEnc);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, func->zName, 0);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->xFinalize ? 1 : 0, 2);
+-	sqlite3VdbeAddOp2(v, OP_Integer, func->nArg, 3);
+-	sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, sname, 0);
+-	sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+-	sqlite3_free (sname);
+-      }
+-    }
+-  }else
+-
+- /*
+   **   PRAGMA table_info(<table>)
+   **
+   ** Return a single row for each column of the named table. The columns of
+@@ -85795,6 +86438,24 @@
+       sqlite3_rekey(db, zKey, i/2);
+     }
+   }else
++/** BEGIN CRYPTO **/
++  if( sqlite3StrICmp(zLeft, "cipher")==0 && zRight ){
++    extern int codec_set_cipher_name(sqlite3*, int, const char *, int);
++    codec_set_cipher_name(db,0,zRight,2); // change cipher for both
++  }else
++  if( sqlite3StrICmp(zLeft, "rekey_cipher")==0 && zRight ){
++    extern int codec_set_cipher_name(sqlite3*, int, const char *, int); 
++    codec_set_cipher_name(db,0,zRight,1); // change write cipher only
++  }else
++  if( sqlite3StrICmp(zLeft, "kdf_iter")==0 && zRight ){
++    extern int codec_set_kdf_iter(sqlite3*, int, int, int);
++    codec_set_kdf_iter(db,0,atoi(zRight),2); // change cipher for both
++  }else
++  if( sqlite3StrICmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
++    extern int codec_set_kdf_iter(sqlite3*, int, int, int); 
++    codec_set_kdf_iter(db,0,atoi(zRight),1); // change write cipher only
++  }else
++/** END CRYPTO **/
+ #endif
+ #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
+   if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
diff --git a/providers/sqlcipher/sqlcipher_specs_add_column.xml.in b/providers/sqlcipher/sqlcipher_specs_add_column.xml.in
new file mode 120000
index 0000000..a255afa
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_add_column.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_add_column.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_auth.xml.in b/providers/sqlcipher/sqlcipher_specs_auth.xml.in
new file mode 100644
index 0000000..bd7df0f
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_auth.xml.in
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<data-set-spec>
+  <parameters>
+    <parameter id="PASSWORD" _name="Passphrase" _descr="Encryption passphrase" gdatype="gchararray" nullok="TRUE" plugin="string:HIDDEN=true"/>
+  </parameters>
+</data-set-spec>
diff --git a/providers/sqlcipher/sqlcipher_specs_create_db.xml.in b/providers/sqlcipher/sqlcipher_specs_create_db.xml.in
new file mode 120000
index 0000000..c8f1a76
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_db.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_create_db.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_create_index.xml.in b/providers/sqlcipher/sqlcipher_specs_create_index.xml.in
new file mode 120000
index 0000000..6c95c53
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_index.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_create_index.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_create_table.xml.in b/providers/sqlcipher/sqlcipher_specs_create_table.xml.in
new file mode 120000
index 0000000..3cef9c3
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_table.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_create_table.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_create_view.xml.in b/providers/sqlcipher/sqlcipher_specs_create_view.xml.in
new file mode 120000
index 0000000..cdfeefc
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_create_view.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_create_view.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_db.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_db.xml.in
new file mode 120000
index 0000000..3a6f43d
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_db.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_db.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_index.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_index.xml.in
new file mode 120000
index 0000000..2c6daab
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_index.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_index.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_table.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_table.xml.in
new file mode 120000
index 0000000..57b73f4
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_table.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_table.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_drop_view.xml.in b/providers/sqlcipher/sqlcipher_specs_drop_view.xml.in
new file mode 120000
index 0000000..ba154ff
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_drop_view.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_drop_view.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_dsn.xml.in b/providers/sqlcipher/sqlcipher_specs_dsn.xml.in
new file mode 120000
index 0000000..5b59709
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_dsn.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_dsn.xml.in
\ No newline at end of file
diff --git a/providers/sqlcipher/sqlcipher_specs_rename_table.xml.in b/providers/sqlcipher/sqlcipher_specs_rename_table.xml.in
new file mode 120000
index 0000000..63874b7
--- /dev/null
+++ b/providers/sqlcipher/sqlcipher_specs_rename_table.xml.in
@@ -0,0 +1 @@
+../sqlite/sqlite_specs_rename_table.xml.in
\ No newline at end of file



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