Exemple #1
0
        static bool Run(List<string> args, Dictionary<string, string> options, bool first)
        {
            string allowedChars = ValidFilenameChars;
            if (options.ContainsKey("extended-chars"))
                allowedChars += options["extended-chars"];
            else
                allowedChars += ExtendedChars;

            bool autoCreateFolders = Library.Utility.Utility.ParseBoolOption(options, "auto-create-folder");

            Library.Interface.IBackend backend = Library.DynamicLoader.BackendLoader.GetBackend(args[0], options);
            if (backend == null)
            {
                Console.WriteLine("Unsupported backend");
                Console.WriteLine();
                Console.WriteLine("Supported backends: " + string.Join(",", XervBackup.Library.DynamicLoader.BackendLoader.Keys));
                return false;
            }

            string disabledModulesValue;
            string enabledModulesValue;
            options.TryGetValue("enable-module", out enabledModulesValue);
            options.TryGetValue("disable-module", out disabledModulesValue);
            string[] enabledModules = enabledModulesValue == null ? new string[0] : enabledModulesValue.Trim().ToLower().Split(',');
            string[] disabledModules = disabledModulesValue == null ? new string[0] : disabledModulesValue.Trim().ToLower().Split(',');

            List<Library.Interface.IGenericModule> loadedModules = new List<IGenericModule>();
            foreach (Library.Interface.IGenericModule m in Library.DynamicLoader.GenericLoader.Modules)
                if (Array.IndexOf<string>(disabledModules, m.Key.ToLower()) < 0 && (m.LoadAsDefault || Array.IndexOf<string>(enabledModules, m.Key.ToLower()) >= 0))
                {
                    m.Configure(options);
                    loadedModules.Add(m);
                }

            try
            {
                List<Library.Interface.IFileEntry> curlist = null;
                try
                {
                    curlist = backend.List();
                }
                catch (FolderMissingException fex)
                {
                    if (autoCreateFolders)
                    {
                        try
                        {
                            if (backend is IBackend_v2)
                                ((IBackend_v2)backend).CreateFolder();

                            curlist = backend.List();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Autocreate folder failed with message: " + ex.Message);
                        }
                    }

                    if (curlist == null)
                        throw fex;
                }

                foreach (Library.Interface.IFileEntry fe in curlist)
                    if (!fe.IsFolder)
                    {
                        if (Library.Utility.Utility.ParseBoolOption(options, "auto-clean") && first)
                            if (Library.Utility.Utility.ParseBoolOption(options, "force"))
                            {
                                Console.WriteLine("Auto clean, removing file: {0}", fe.Name);
                                backend.Delete(fe.Name);
                                continue;
                            }
                            else
                                Console.WriteLine("Specify the --force flag to actually delete files");

                        Console.WriteLine("*** Remote folder is not empty, aborting");
                        return false;
                    }

                int number_of_files = 10;
                int min_file_size = 1024;
                int max_file_size = 1024 * 1024 * 50;
                int min_filename_size = 5;
                int max_filename_size = 80;
                bool disableStreaming = Library.Utility.Utility.ParseBoolOption(options, "disable-streaming-transfers");
                bool skipOverwriteTest = Library.Utility.Utility.ParseBoolOption(options, "skip-overwrite-test");

                if (options.ContainsKey("number-of-files"))
                    number_of_files = int.Parse(options["number-of-files"]);
                if (options.ContainsKey("min-file-size"))
                    min_file_size = (int)XervBackup.Library.Utility.Sizeparser.ParseSize(options["min-file-size"], "mb");
                if (options.ContainsKey("max-file-size"))
                    max_file_size = (int)XervBackup.Library.Utility.Sizeparser.ParseSize(options["max-file-size"]);

                if (options.ContainsKey("min-filename-length"))
                    min_filename_size = int.Parse(options["min-filename-length"]);
                if (options.ContainsKey("max-filename-length"))
                    max_filename_size = int.Parse(options["max-filename-length"]);

                Random rnd = new Random();
                System.Security.Cryptography.SHA256 sha = System.Security.Cryptography.SHA256.Create();

                //Create random files
                using (Library.Utility.TempFolder tf = new XervBackup.Library.Utility.TempFolder())
                {
                    List<TempFile> files = new List<TempFile>();
                    for (int i = 0; i < number_of_files; i++)
                    {

                        StringBuilder filename = new StringBuilder();
                        int filenamelen = rnd.Next(min_filename_size, max_filename_size);
                        for (int j = 0; j < filenamelen; j++)
                            filename.Append(allowedChars[rnd.Next(0, allowedChars.Length)]);

                        string localfilename = CreateRandomFile(tf, i, min_file_size, max_file_size, rnd);

                        //Calculate local hash and length
                        using (System.IO.FileStream fs = new System.IO.FileStream(localfilename, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                            files.Add(new TempFile(filename.ToString(), localfilename, sha.ComputeHash(fs), fs.Length));
                    }

                    byte[] dummyFileHash = null;
                    if (!skipOverwriteTest)
                    {
                        Console.WriteLine("Uploading wrong files ...");
                        using (Library.Utility.TempFile dummy = new Library.Utility.TempFile(CreateRandomFile(tf, files.Count, 1024, 2048, rnd)))
                        {
                            using (System.IO.FileStream fs = new System.IO.FileStream(dummy, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                                dummyFileHash = sha.ComputeHash(fs);

                            //Upload a dummy file for entry 0 and the last one, they will be replaced by the real files afterwards
                            //We upload entry 0 twice just to try to freak any internal cache list
                            Uploadfile(dummy, 0, files[0].remotefilename, backend, disableStreaming);
                            Uploadfile(dummy, 0, files[0].remotefilename, backend, disableStreaming);
                            Uploadfile(dummy, files.Count - 1, files[files.Count - 1].remotefilename, backend, disableStreaming);
                        }

                    }

                    Console.WriteLine("Uploading files ...");

                    for (int i = 0; i < files.Count; i++)
                        Uploadfile(files[i].localfilename, i, files[i].remotefilename, backend, disableStreaming);

                    Console.WriteLine("Verifying file list ...");

                    curlist = backend.List();
                    foreach (Library.Interface.IFileEntry fe in curlist)
                        if (!fe.IsFolder)
                        {
                            bool found = false;
                            foreach (TempFile tx in files)
                                if (tx.remotefilename == fe.Name)
                                {
                                    if (tx.found)
                                        Console.WriteLine("*** File with name {0} was found more than once", tx.remotefilename);
                                    found = true;
                                    tx.found = true;

                                    if (fe.Size > 0 && tx.length != fe.Size)
                                        Console.WriteLine("*** File with name {0} has size {1} but the size was reported as {2}", tx.remotefilename, tx.length, fe.Size);

                                    break;
                                }

                            if (!found)
                                Console.WriteLine("*** File with name {0} was found on server but not uploaded!", fe.Name);
                        }

                    foreach (TempFile tx in files)
                        if (!tx.found)
                            Console.WriteLine("*** File with name {0} was uploaded but not found afterwards", tx.remotefilename);

                    Console.WriteLine("Downloading files");

                    for (int i = 0; i < files.Count; i++)
                    {
                        using (XervBackup.Library.Utility.TempFile cf = new XervBackup.Library.Utility.TempFile())
                        {
                            Exception e = null;
                            Console.Write("Downloading file {0} ... ", i);

                            try
                            {
                                if (backend is Library.Interface.IStreamingBackend && !disableStreaming)
                                {
                                    using (System.IO.FileStream fs = new System.IO.FileStream(cf, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
                                    using (NonSeekableStream nss = new NonSeekableStream(fs))
                                        (backend as Library.Interface.IStreamingBackend).Get(files[i].remotefilename, nss);
                                }
                                else
                                    backend.Get(files[i].remotefilename, cf);

                                e = null;
                            }
                            catch (Exception ex)
                            {
                                e = ex;
                            }

                            if (e != null)
                                Console.WriteLine("failed\n*** Error: {0}", e.ToString());
                            else
                                Console.WriteLine("done");

                            Console.Write("Checking hash ... ");

                            using (System.IO.FileStream fs = new System.IO.FileStream(cf, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                                if (Convert.ToBase64String(sha.ComputeHash(fs)) != Convert.ToBase64String(files[i].hash))
                                {
                                    if (dummyFileHash != null && Convert.ToBase64String(sha.ComputeHash(fs)) == Convert.ToBase64String(dummyFileHash))
                                        Console.WriteLine("failed\n*** Downloaded file was the dummy file");
                                    else
                                        Console.WriteLine("failed\n*** Downloaded file was corrupt");
                                }
                                else
                                    Console.WriteLine("done");
                        }
                    }

                    Console.WriteLine("Deleting files...");

                    foreach (TempFile tx in files)
                        try { backend.Delete(tx.remotefilename); }
                        catch (Exception ex)
                        {
                            Console.WriteLine("*** Failed to delete file {0}, message: {1}", tx.remotefilename, ex.ToString());
                        }

                    curlist = backend.List();
                    foreach (Library.Interface.IFileEntry fe in curlist)
                        if (!fe.IsFolder)
                        {
                            Console.WriteLine("*** Remote folder contains {0} after cleanup", fe.Name);
                        }

                }
            }
            finally
            {
                foreach (Library.Interface.IGenericModule m in loadedModules)
                    if (m is IDisposable)
                        ((IDisposable)m).Dispose();
            }

            return true;
        }
        public void ExecuteTask(IDuplicityTask task)
        {
            Dictionary<string, string> options = new Dictionary<string,string>();

            //Set the log level to be that of the GUI
            options["log-level"] = XervBackup.Library.Logging.Log.LogLevel.ToString();

            string destination = task.GetConfiguration(options);

            string results = "";
            string parsedMessage = "";
            m_isAborted = false;

            try
            {
                //TODO: Its a bit dirty to set the options after creating the instance
                using (Interface i = new Interface(destination, options))
                {
                    lock (m_lock)
                    {
                        m_stopReason = System.Windows.Forms.CloseReason.None;
                        m_currentBackupControlInterface = i;
                    }

                    SetupControlInterface();

                    i.OperationProgress += new OperationProgressEvent(XervBackup_OperationProgress);

                    switch (task.TaskType)
                    {
                        case DuplicityTaskType.FullBackup:
                        case DuplicityTaskType.IncrementalBackup:
                            {
                                //Activate auto-cleanup
                                options["auto-cleanup"] = "";
                                options["force"] = "";
                                if (task.Schedule.Task.KeepFull > 0)
                                    m_extraOperations++;
                                if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                                    m_extraOperations++;

                                Library.Utility.TempFolder tf = null;
                                try
                                {
                                    if (ProgressEvent != null)
                                        ProgressEvent(XervBackupOperation.Backup, RunnerState.Started, task.Schedule.Name, "", 0, -1);

                                    if (task.Task.IncludeSetup)
                                    {
                                        //Make a copy of the current database
                                        tf = new XervBackup.Library.Utility.TempFolder();
                                        string filename = System.IO.Path.Combine(tf, System.IO.Path.GetFileName(Program.DatabasePath));

                                        System.IO.File.Copy(Program.DatabasePath, filename, true);
                                        using (System.Data.IDbConnection con = (System.Data.IDbConnection)Activator.CreateInstance(SQLiteLoader.SQLiteConnectionType))
                                        {
                                            con.ConnectionString = "Data Source=" + filename;

                                            //Open the database, handle any encryption issues automatically
                                            Program.OpenDatabase(con);

                                            using (System.Data.IDbCommand cmd = con.CreateCommand())
                                            {
                                                //Remove all log data to minimize the size of the database
                                                cmd.CommandText = "DELETE FROM CommandQueue;";
                                                cmd.ExecuteNonQuery();
                                                cmd.CommandText = "DELETE FROM Log;";
                                                cmd.ExecuteNonQuery();
                                                cmd.CommandText = "DELETE FROM LogBlob;";
                                                cmd.ExecuteNonQuery();

                                                //Free up unused space
                                                cmd.CommandText = "VACUUM;";
                                                cmd.ExecuteNonQuery();
                                            }
                                        }

                                        options["signature-control-files"] = filename;
                                    }

                                    options["full-if-sourcefolder-changed"] = "";

                                    List<KeyValuePair<bool, string>> filters = new List<KeyValuePair<bool, string>>();
                                    string[] sourceFolders = DynamicSetupHelper.GetSourceFolders(task.Task, new ApplicationSettings(task.Task.DataParent), filters);

                                    if (options.ContainsKey("filter"))
                                        filters.AddRange(Library.Utility.FilenameFilter.DecodeFilter(options["filter"]));

                                    options["filter"] = Library.Utility.FilenameFilter.EncodeAsFilter(filters);

                                    //At this point we register the backup as being in progress
                                    ((FullOrIncrementalTask)task).WriteBackupInProgress(Strings.XervBackupRunner.ShutdownWhileBackupInprogress);

                                    results = i.Backup(sourceFolders);
                                }
                                finally
                                {
                                    if (tf != null)
                                        tf.Dispose();

                                    if (ProgressEvent != null)
                                        ProgressEvent(XervBackupOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                                }
                                break;
                            }
                        case DuplicityTaskType.ListBackups:

                            List<string> res = new List<string>();
                            foreach (ManifestEntry be in i.GetBackupSets())
                            {
                                res.Add(be.Time.ToString());
                                foreach (ManifestEntry bei in be.Incrementals)
                                    res.Add(bei.Time.ToString());
                            }

                            (task as ListBackupsTask).Backups = res.ToArray();
                            break;
                        case DuplicityTaskType.ListBackupEntries:
                            (task as ListBackupEntriesTask).Backups = i.GetBackupSets();
                            break;
                        case DuplicityTaskType.ListFiles:
                            (task as ListFilesTask).Files = i.ListCurrentFiles();
                            break;
                        case DuplicityTaskType.ListSourceFolders:
                            (task as ListSourceFoldersTask).Files = new List<string>(i.ListSourceFolders() ?? new string[0]);
                            break;
                        case DuplicityTaskType.ListActualFiles:
                            (task as ListActualFilesTask).Files = i.ListActualSignatureFiles();
                            break;
                        case DuplicityTaskType.RemoveAllButNFull:
                            results = i.DeleteAllButNFull();
                            break;
                        case DuplicityTaskType.RemoveOlderThan:
                            results = i.DeleteOlderThan();
                            break;
                        case DuplicityTaskType.Restore:
                            options["file-to-restore"] = ((RestoreTask)task).SourceFiles;
                            if (options.ContainsKey("filter"))
                                options.Remove("filter");

                            try
                            {
                                if (ProgressEvent != null)
                                    ProgressEvent(XervBackupOperation.Restore, RunnerState.Started, task.Schedule.Name, "", 0, -1);
                                results = i.Restore(task.LocalPath.Split(System.IO.Path.PathSeparator));
                            }
                            finally
                            {
                                if (ProgressEvent != null)
                                    ProgressEvent(XervBackupOperation.Restore, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                            }
                            break;

                        case DuplicityTaskType.RestoreSetup:
                            i.RestoreControlFiles(task.LocalPath);
                            break;
                        default:
                            return;
                    }
                }
            }
            catch (Exception ex)
            {
                while (ex is System.Reflection.TargetInvocationException && ex.InnerException != null)
                    ex = ex.InnerException;

                if (ex is System.Threading.ThreadAbortException)
                {
                    m_isAborted = true;
                    System.Threading.Thread.ResetAbort();
                }
                else if (ex is Library.Main.LiveControl.ExecutionStoppedException)
                    m_isAborted = true;

                if (m_isAborted && m_stopReason != System.Windows.Forms.CloseReason.None)
                {
                    //If the user has stopped the backup for some reason, write a nicer message
                    switch (m_stopReason)
                    {
                        case System.Windows.Forms.CloseReason.ApplicationExitCall:
                            parsedMessage = Strings.XervBackupRunner.ApplicationExitLogMesssage;
                            break;
                        case System.Windows.Forms.CloseReason.TaskManagerClosing:
                            parsedMessage = Strings.XervBackupRunner.TaskManagerCloseMessage;
                            break;
                        case System.Windows.Forms.CloseReason.UserClosing:
                            parsedMessage = Strings.XervBackupRunner.UserClosingMessage;
                            break;
                        case System.Windows.Forms.CloseReason.WindowsShutDown:
                            parsedMessage = Strings.XervBackupRunner.WindowsShutdownMessage;
                            break;
                        default:
                            parsedMessage = string.Format(Strings.XervBackupRunner.OtherAbortMessage, m_stopReason);
                            break;
                    }

                    if (task.Schedule != null)
                    {
                        //If the application is going down, the backup should resume on next launch
                        switch (m_stopReason)
                        {
                            case System.Windows.Forms.CloseReason.ApplicationExitCall:
                            case System.Windows.Forms.CloseReason.TaskManagerClosing:
                            case System.Windows.Forms.CloseReason.WindowsShutDown:
                                task.Schedule.ScheduledRunFailed();
                                break;
                        }
                    }
                }
                else
                    parsedMessage = string.Format(Strings.XervBackupRunner.ErrorMessage, ex.Message);

                results = "Error: " + ex.ToString(); //Don't localize

                while (ex.InnerException != null)
                {
                    ex = ex.InnerException;
                    results += Environment.NewLine + "InnerError: " + ex.ToString(); //Don't localize
                }

            }
            finally
            {
                lock (m_lock)
                    m_currentBackupControlInterface = null;
            }

            try
            {
                if (!m_isAborted && (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup))
                {
                    if (task.Schedule.Task.KeepFull > 0)
                    {
                        m_lastPGProgress = 100;
                        m_lastPGmessage = Strings.XervBackupRunner.CleaningUpMessage;
                        m_lastPGSubmessage = "";
                        m_lastPGSubprogress = -1;

                        ReinvokeLastProgressEvent();
                        m_extraOperations--;

                        RemoveAllButNFullTask tmpTask = new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.Task.KeepFull);
                        ExecuteTask(tmpTask);
                        results += Environment.NewLine + Strings.XervBackupRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result;
                    }

                    if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                    {
                        m_lastPGProgress = 100;
                        m_lastPGmessage = Strings.XervBackupRunner.CleaningUpMessage;
                        m_lastPGSubmessage = "";
                        m_lastPGSubprogress = -1;

                        ReinvokeLastProgressEvent();
                        m_extraOperations--;

                        RemoveOlderThanTask tmpTask = new RemoveOlderThanTask(task.Schedule, task.Schedule.Task.KeepTime);
                        ExecuteTask(tmpTask);
                        results += Environment.NewLine + Strings.XervBackupRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result;
                    }

                    if (task.Schedule.Task.KeepFull > 0 || !string.IsNullOrEmpty(task.Schedule.Task.KeepTime))
                        ReinvokeLastProgressEvent();

                    if (ProgressEvent != null)
                        ProgressEvent(XervBackupOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1);
                }
            }
            catch (Exception ex)
            {
                results += Environment.NewLine + string.Format(Strings.XervBackupRunner.CleanupError, ex.Message);
            }

            task.IsAborted = m_isAborted;
            task.Result = results;
            task.RaiseTaskCompleted(results, parsedMessage);

            if (ResultEvent != null && task is FullBackupTask || task is IncrementalBackupTask)
            {
                Log[] logs = Program.DataConnection.GetObjects<Log>("TaskID = ? AND SubAction LIKE ? ORDER BY EndTime DESC", task.Task.ID, "Primary");
                if (logs != null && logs.Length > 0)
                {
                    Datamodel.Log l = logs[0];
                    RunnerResult r = RunnerResult.Error;
                    if (l.ParsedStatus == XervBackupOutputParser.ErrorStatus)
                        r = RunnerResult.Error;
                    else if (l.ParsedStatus == XervBackupOutputParser.OKStatus || l.ParsedStatus == XervBackupOutputParser.NoChangedFiles)
                        r = RunnerResult.OK;
                    else if (l.ParsedStatus == XervBackupOutputParser.PartialStatus)
                        r = RunnerResult.Partial;
                    else if (l.ParsedStatus == XervBackupOutputParser.WarningStatus)
                        r = RunnerResult.Warning;

                    ResultEvent(r, parsedMessage, results);
                }
            }

            if (task.Schedule != null && !m_isAborted)
                task.Schedule.ScheduledRunCompleted(); //Register as completed if not aborted
        }
        private void Restore(object sender, DoWorkEventArgs args)
        {
            System.Data.LightDatamodel.DataFetcherNested con = new System.Data.LightDatamodel.DataFetcherNested(Program.DataConnection);
            Schedule s = con.Add<Schedule>();
            s.Task = con.Add<Task>();
            m_wrapper.UpdateSchedule(s);

            using (Library.Utility.TempFolder tf = new XervBackup.Library.Utility.TempFolder())
            {
                RestoreSetupTask task = new RestoreSetupTask(s, tf);
                Dictionary<string, string> options = new Dictionary<string, string>();
                string destination  = task.GetConfiguration(options);
                Library.Main.Interface.RestoreControlFiles(destination, task.LocalPath, options);

                string filename = System.IO.Path.Combine(tf, System.IO.Path.GetFileName(Program.DatabasePath));
                if (System.IO.File.Exists(filename))
                {
                    //Connect to the downloaded database
                    using (System.Data.IDbConnection scon = (System.Data.IDbConnection)Activator.CreateInstance(SQLiteLoader.SQLiteConnectionType))
                    {
                        scon.ConnectionString = "Data Source=" + filename;

                        //Make sure encryption etc is handled correctly
                        Program.OpenDatabase(scon);

                        //Upgrade the database to the current version
                        DatabaseUpgrader.UpgradeDatabase(scon, filename);
                    }

                    //Shut down this connection
                    Program.LiveControl.Pause();
                    Program.DataConnection.ClearCache();
                    //We also need to remove any dirty objects as the ClearCache maintains those
                    foreach (System.Data.LightDatamodel.IDataClass o in Program.DataConnection.LocalCache.GetAllChanged())
                        Program.DataConnection.DiscardObject(o);
                    Program.DataConnection.Provider.Connection.Close();

                    //Replace the existing database with this one
                    System.IO.File.Copy(filename, Program.DatabasePath, true);

                    //Re-start the connection, using the new file
                    Program.DataConnection.Provider.Connection = (System.Data.IDbConnection)Activator.CreateInstance(SQLiteLoader.SQLiteConnectionType);
                    Program.DataConnection.Provider.Connection.ConnectionString = "Data Source=" + Program.DatabasePath;
                    Program.OpenDatabase(Program.DataConnection.Provider.Connection);

                    //Remove the downloaded database
                    try { System.IO.File.Delete(filename); }
                    catch { }
                }
                else
                    throw new Exception(Strings.FinishedRestoreSetup.SetupFileMissingError);

                NormalizeApplicationSettings();

                Program.Scheduler.Reschedule();
            }
        }
Exemple #4
0
        private static bool RunBackup(string[] args, XervBackup.Scheduler.Data.HistoryDataSet.HistoryRow aHistoryRow)
        {
            // Log the start
            Library.Logging.Log.WriteMessage(Name + " " + String.Join(" ", args) + (itsDryRun ? " DryRun as" : " as ") + XervBackup.Scheduler.Utility.User.UserName,
                XervBackup.Library.Logging.LogMessageType.Information);

            // See if the XML file name was on the command line
            string XML = (args.Length > 1) ? XML = args[1] : XervBackup.Scheduler.Data.SchedulerDataSet.DefaultPath();
            // Convert our options to XervBackup options
            Options BackupOptions = new Options(Job, XML);
            // Get disabled monitors
            DisabledMonitors = BackupOptions.DisabledMonitors;
            // Complain about any results from the drive mapping
            if (!string.IsNullOrEmpty(BackupOptions.MapResults))
                Library.Logging.Log.WriteMessage(BackupOptions.MapResults, XervBackup.Library.Logging.LogMessageType.Information);

            // Get the signature file temp
            XervBackup.Library.Utility.TempFolder SigTemp = new XervBackup.Library.Utility.TempFolder();
            string SigThingy = System.IO.Path.Combine(SigTemp, XervBackup.Scheduler.Data.SchedulerDataSet.DefaultName);
            if (XervBackup.Scheduler.Utility.Tools.NoException((Action)delegate() { System.IO.File.Copy(XervBackup.Scheduler.Data.SchedulerDataSet.DefaultPath(), SigThingy); }))
                BackupOptions["signature-control-files"] = SigThingy;

            // See if there is a pipe server listening, if so, connect to it for progress messages
            bool HasPipe = XervBackup.Scheduler.Utility.NamedPipeServerStream.ServerIsUp(
                XervBackup.Scheduler.Utility.NamedPipeServerStream.MakePipeName(PipeBaseName, XervBackup.Scheduler.Utility.User.UserName, System.IO.Pipes.PipeDirection.In));
            if (HasPipe) Pipe.Connecter();
            // Run the dern thing already
            string Result = "Not started";
            bool OK = false;
            if (itsDryRun)
            {
                OK = true;
                Result = "DryRun";
                if(HasPipe) TestProgress(5); // Just send fake progress
            }
            else
            {
                try
                {
                    using (XervBackup.Library.Main.Interface i = new XervBackup.Library.Main.Interface(BackupOptions.Target, BackupOptions))
                    {
                        // Set our events if we have a pipe
                        if (HasPipe)
                        {
                            i.OperationProgress += new XervBackup.Library.Main.OperationProgressEvent(Pipe.OperationProgress);
                            i.OperationCompleted += new XervBackup.Library.Main.OperationProgressEvent(Pipe.OperationProgress);
                        }
                        Result = i.Backup(BackupOptions.Source);
                    }
                    OK = true;
                }
                catch (Exception Ex)
                {
                    // Dang
                    Result = "Error: " + Ex.Message;
                }
            }
            // Log the done.
            Library.Logging.Log.WriteMessage("Finished: "+(OK?"OK":Result), OK ? XervBackup.Library.Logging.LogMessageType.Information : XervBackup.Library.Logging.LogMessageType.Error);
            // Put deletions in the log, where they belong.
            // Deleting backup at 07/06/2011 06:05:21
            foreach(string Line in Result.Split('\n'))
                if (Line.StartsWith("Deleting backup at "))
                    Library.Logging.Log.WriteMessage(Line, XervBackup.Library.Logging.LogMessageType.Information);
            // OK, made it, update the history
            aHistoryRow.Update("Backup", BackupOptions.Full, OK, Result, BackupOptions.Checksum, BackupOptions.CheckMod);
            LimitLogFiles(BackupOptions.LogFileMaxAgeDays); // zero has no effect.
            // woot
            return OK;
        }