/// <summary> /// Backup the database /// </summary> public string Backup(string passkey) { // Take the main connection lock lock (s_lockObject) { try { var backupDir = Path.Combine(Path.GetTempPath(), "db-copy"); if (!Directory.Exists(backupDir)) { Directory.CreateDirectory(backupDir); } ISQLitePlatform platform = ApplicationContext.Current.GetService <ISQLitePlatform>(); var connectionStrings = (ApplicationContext.Current.GetService <IConfigurationManager>()).GetSection <DcDataConfigurationSection>().ConnectionString; for (var i = 0; i < connectionStrings.Count; i++) { var pool = this.GetConnectionPool(connectionStrings[i].Name); //pool.CloseAll(); using (pool.Lock()) // Lock the pool { this.m_tracer.TraceInfo("Will backup {0} with passkey {1}", connectionStrings[i].GetComponent("dbfile"), !String.IsNullOrEmpty(passkey)); if (!File.Exists(connectionStrings[i].GetComponent("dbfile"))) { continue; } var dataFile = connectionStrings[i].GetComponent("dbfile"); ApplicationContext.Current.SetProgress(Strings.locale_backup, (float)i / connectionStrings.Count); var backupFile = Path.Combine(backupDir, Path.GetFileName(dataFile)); if (File.Exists(backupFile)) { File.Delete(backupFile); } // Create empty database this.m_tracer.TraceVerbose("Creating temporary copy of database at {0}...", backupFile); // Create new encrypted database Mono.Data.Sqlite.SqliteConnection.CreateFile(backupFile); using (var prodConn = new Mono.Data.Sqlite.SqliteConnection($"Data Source={backupFile}")) { prodConn.Open(); using (var cmd = prodConn.CreateCommand()) { cmd.CommandType = System.Data.CommandType.Text; cmd.CommandText = $"PRAGMA key = '{passkey}'"; cmd.ExecuteNonQuery(); } } // Commands to be run string[] sqlScript = { $"ATTACH DATABASE '{backupFile}' AS bak_db KEY '{passkey}'", "SELECT sqlcipher_export('bak_db')", "DETACH DATABASE bak_db" }; // Attempt to use the existing security key using (var bakConn = new Mono.Data.Sqlite.SqliteConnection($"Data Source={dataFile}")) { if (connectionStrings[i].GetComponent("encrypt") == "true") { bakConn.SetPassword(ApplicationContext.Current.GetCurrentContextSecurityKey()); } bakConn.Open(); foreach (var sql in sqlScript) { using (var cmd = bakConn.CreateCommand()) { cmd.CommandType = System.Data.CommandType.Text; cmd.CommandText = sql; cmd.ExecuteNonQuery(); } } } } } return(backupDir); } catch (Exception e) { throw new DataPersistenceException("Error backing up database", e); } } }