Ejemplo n.º 1
0
        /// <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);
                }
            }
        }