public void ExecuteTask(IDuplicityTask task) { System.Diagnostics.Process p = new System.Diagnostics.Process(); p.StartInfo = SetupEnv(task); p.Start(); p.WaitForExit(); string errorstream = p.StandardError.ReadToEnd(); string outstream = p.StandardOutput.ReadToEnd(); string logentry = ""; if (!string.IsNullOrEmpty(errorstream)) { string tmp = errorstream.Replace("gpg: CAST5 encrypted data", "").Replace("gpg: encrypted with 1 passphrase", "").Trim(); if (tmp.Length > 0) logentry += "** Error stream: \r\n" + errorstream + "\r\n**\r\n"; } logentry += outstream; task.RaiseTaskCompleted(logentry); if (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup) { if (task.Schedule.KeepFull > 0) ExecuteTask(new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.KeepFull)); if (!string.IsNullOrEmpty(task.Schedule.KeepTime)) ExecuteTask(new RemoveOlderThanTask(task.Schedule, task.Schedule.KeepTime)); } }
void ListBackupsTask_TaskCompleted(IDuplicityTask owner, string output, string parsedMessage) { if (string.IsNullOrEmpty(output)) { return; } const string DIVIDER = "-------------------------\r\n"; const string HEADERS = " Type of backup set: Time: Num volumes:"; List <string> res = new List <string>(); foreach (string part in output.Split(new string[] { DIVIDER }, StringSplitOptions.RemoveEmptyEntries)) { if (part.IndexOf(HEADERS) >= 0) { bool passedHeader = false; foreach (string line in part.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)) { if (line.StartsWith(HEADERS)) { passedHeader = true; } else if (passedHeader) { string tmp = line.Trim(); if (tmp.StartsWith("Full")) { tmp = tmp.Substring("Full".Length).Trim(); } else if (tmp.StartsWith("Incremental")) { tmp = tmp.Substring("Incremental".Length).Trim(); } string datetime = tmp.Substring(0, tmp.LastIndexOf(' ')).Trim(); /*DateTime dt; * if (DateTime.TryParse(datetime, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt))*/ res.Add(datetime); } } } } //System.Text.RegularExpressions.Regex regexp = new System.Text.RegularExpressions.Regex("---------------- m_backups = res.ToArray(); }
private System.Diagnostics.ProcessStartInfo SetupEnv(IDuplicityTask task) { task.BeginTime = DateTime.Now; List <string> args = new List <string>(); System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(); StringDictionary env = psi.EnvironmentVariables; foreach (string key in m_environment.Keys) { env[key] = m_environment[key]; } env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.NcFTPPath) + System.IO.Path.PathSeparator + env["PATH"]; env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PuttyPath) + System.IO.Path.PathSeparator + env["PATH"]; env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PGPPath) + System.IO.Path.PathSeparator + env["PATH"]; args.Add("\"" + System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.DuplicityPath) + "\""); task.GetArguments(args); if (string.IsNullOrEmpty(task.Task.Encryptionkey)) { args.Add("--no-encryption"); } else { env["PASSPHRASE"] = task.Task.Encryptionkey; } task.Task.GetExtraSettings(args, env); psi.CreateNoWindow = true; psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; psi.FileName = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PythonPath); psi.RedirectStandardError = true; psi.RedirectStandardOutput = true; psi.RedirectStandardInput = false; psi.UseShellExecute = false; psi.WorkingDirectory = System.IO.Path.GetDirectoryName(psi.FileName); psi.Arguments = string.Join(" ", args.ToArray()); return(psi); }
public void ExecuteTask(IDuplicityTask task) { System.Diagnostics.Process p = new System.Diagnostics.Process(); p.StartInfo = SetupEnv(task); p.Start(); p.WaitForExit(); string errorstream = p.StandardError.ReadToEnd(); string outstream = p.StandardOutput.ReadToEnd(); string logentry = ""; if (!string.IsNullOrEmpty(errorstream)) { string tmp = errorstream.Replace("gpg: CAST5 encrypted data", "").Replace("gpg: encrypted with 1 passphrase", "").Trim(); if (tmp.Length > 0) { logentry += "** Error stream: \r\n" + errorstream + "\r\n**\r\n"; } } logentry += outstream; task.RaiseTaskCompleted(logentry); if (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup) { if (task.Schedule.KeepFull > 0) { ExecuteTask(new RemoveAllButNFullTask(task.Schedule, (int)task.Schedule.KeepFull)); } if (!string.IsNullOrEmpty(task.Schedule.KeepTime)) { ExecuteTask(new RemoveOlderThanTask(task.Schedule, task.Schedule.KeepTime)); } } }
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"] = Duplicati.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(Duplicati_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(DuplicatiOperation.Backup, RunnerState.Started, task.Schedule.Name, "", 0, -1); if (task.Task.IncludeSetup) { //Make a copy of the current database tf = new Duplicati.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.DuplicatiRunner.ShutdownWhileBackupInprogress); results = i.Backup(sourceFolders); } finally { if (tf != null) tf.Dispose(); if (ProgressEvent != null) ProgressEvent(DuplicatiOperation.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(DuplicatiOperation.Restore, RunnerState.Started, task.Schedule.Name, "", 0, -1); results = i.Restore(task.LocalPath.Split(System.IO.Path.PathSeparator)); } finally { if (ProgressEvent != null) ProgressEvent(DuplicatiOperation.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.DuplicatiRunner.ApplicationExitLogMesssage; break; case System.Windows.Forms.CloseReason.TaskManagerClosing: parsedMessage = Strings.DuplicatiRunner.TaskManagerCloseMessage; break; case System.Windows.Forms.CloseReason.UserClosing: parsedMessage = Strings.DuplicatiRunner.UserClosingMessage; break; case System.Windows.Forms.CloseReason.WindowsShutDown: parsedMessage = Strings.DuplicatiRunner.WindowsShutdownMessage; break; default: parsedMessage = string.Format(Strings.DuplicatiRunner.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.DuplicatiRunner.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.DuplicatiRunner.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.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result; } if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime)) { m_lastPGProgress = 100; m_lastPGmessage = Strings.DuplicatiRunner.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.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result; } if (task.Schedule.Task.KeepFull > 0 || !string.IsNullOrEmpty(task.Schedule.Task.KeepTime)) ReinvokeLastProgressEvent(); if (ProgressEvent != null) ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1); } } catch (Exception ex) { results += Environment.NewLine + string.Format(Strings.DuplicatiRunner.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 == DuplicatiOutputParser.ErrorStatus) r = RunnerResult.Error; else if (l.ParsedStatus == DuplicatiOutputParser.OKStatus || l.ParsedStatus == DuplicatiOutputParser.NoChangedFiles) r = RunnerResult.OK; else if (l.ParsedStatus == DuplicatiOutputParser.PartialStatus) r = RunnerResult.Partial; else if (l.ParsedStatus == DuplicatiOutputParser.WarningStatus) r = RunnerResult.Warning; ResultEvent(r, parsedMessage, results); } } if (task.Schedule != null && !m_isAborted) task.Schedule.ScheduledRunCompleted(); //Register as completed if not aborted }
void DoneEvent(IDuplicityTask owner, string output, string parsedMessage) { WriteLogMessage("Backup", "Cleanup", output, parsedMessage, false, null); }
void ListBackupsTask_TaskCompleted(IDuplicityTask owner, string output, string parsedMessage) { if (string.IsNullOrEmpty(output)) return; const string DIVIDER = "-------------------------\r\n"; const string HEADERS = " Type of backup set: Time: Num volumes:"; List<string> res = new List<string>(); foreach (string part in output.Split(new string[] { DIVIDER }, StringSplitOptions.RemoveEmptyEntries)) if (part.IndexOf(HEADERS) >= 0) { bool passedHeader = false; foreach (string line in part.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)) { if (line.StartsWith(HEADERS)) passedHeader = true; else if (passedHeader) { string tmp = line.Trim(); if (tmp.StartsWith("Full")) tmp = tmp.Substring("Full".Length).Trim(); else if (tmp.StartsWith("Incremental")) tmp = tmp.Substring("Incremental".Length).Trim(); string datetime = tmp.Substring(0, tmp.LastIndexOf(' ')).Trim(); /*DateTime dt; if (DateTime.TryParse(datetime, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dt))*/ res.Add(datetime); } } } //System.Text.RegularExpressions.Regex regexp = new System.Text.RegularExpressions.Regex("---------------- m_backups = res.ToArray(); }
protected void DoneEvent(IDuplicityTask task, string output, string parsedMessage) { WriteLogMessage("Backup", "Primary", output, parsedMessage, true, m_log); m_log = null; }
void DoneEvent(IDuplicityTask owner, string output, string parsedMessage) { WriteLogMessage("Restore", "Primary", output, parsedMessage, true, null); }
/// <summary> /// The actual scheduling procedure /// </summary> private void Runner() { while (!m_terminate) { List <Schedule> reps = new List <Schedule>(); List <Schedule> tmp; lock (m_datalock) tmp = new List <Schedule>(m_connection.GetObjects <Schedule>()); //Determine schedule list foreach (Schedule sc in tmp) { if (!string.IsNullOrEmpty(sc.Repeat)) { DateTime start = sc.NextScheduledTime; try { start = GetNextValidTime(sc.NextScheduledTime, sc.Repeat, sc.AllowedWeekdays); } catch { } //TODO: Report this somehow //If time is exceeded, run it now if (start <= DateTime.Now) { //See if it is already queued List <IDuplicityTask> tmplst = m_worker.CurrentTasks; IDuplicityTask tastTemp = m_worker.CurrentTask; if (tastTemp != null) { tmplst.Add(tastTemp); } bool found = false; foreach (IDuplicityTask t in tmplst) { if (t != null && t is IncrementalBackupTask && ((IncrementalBackupTask)t).Schedule.ID == sc.ID) { found = true; break; } } //If it is not already in queue, put it there if (!found) { m_worker.AddTask(new IncrementalBackupTask(sc)); } //Caluclate next time, by adding the interval to the start until we have // passed the current date and time //TODO: Make this more efficient int i = 50000; while (start <= DateTime.Now && i-- > 0) { try { start = GetNextValidTime(Timeparser.ParseTimeInterval(sc.Repeat, start), sc.Repeat, sc.AllowedWeekdays); } catch { //TODO: Report this somehow continue; } } if (start < DateTime.Now) { continue; } } //Add to schedule list at the new time reps.Add(sc); sc.NextScheduledTime = start; } } System.Data.LightDatamodel.QueryModel.OperationOrParameter op = System.Data.LightDatamodel.QueryModel.Parser.ParseQuery("ORDER BY When ASC"); //Sort them, lock as we assign the m_schedule variable lock (m_lock) m_schedule = op.EvaluateList <Schedule>(reps).ToArray(); //Raise event if needed if (NewSchedule != null) { NewSchedule(this, null); } int waittime = 0; //Figure out a sensible amount of time to sleep the thread if (m_schedule.Length > 0) { //When is the next run scheduled? TimeSpan nextrun = m_schedule[0].NextScheduledTime - DateTime.Now; if (nextrun.TotalMilliseconds < 0) { continue; } //Don't sleep for more than 5 minutes waittime = (int)Math.Min(nextrun.TotalMilliseconds, 60 * 1000 * 5); } else { //No tasks, check back later waittime = 60 * 1000; } //Waiting on the event, enables a wakeup call from termination // never use waittime = 0 m_event.WaitOne(Math.Max(100, waittime), false); } }
private System.Diagnostics.ProcessStartInfo SetupEnv(IDuplicityTask task) { task.BeginTime = DateTime.Now; List<string> args = new List<string>(); System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(); StringDictionary env = psi.EnvironmentVariables; foreach (string key in m_environment.Keys) env[key] = m_environment[key]; env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.NcFTPPath) + System.IO.Path.PathSeparator + env["PATH"]; env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PuttyPath) + System.IO.Path.PathSeparator + env["PATH"]; env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PGPPath) + System.IO.Path.PathSeparator + env["PATH"]; args.Add("\"" + System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.DuplicityPath) + "\""); task.GetArguments(args); if (string.IsNullOrEmpty(task.Task.Encryptionkey)) args.Add("--no-encryption"); else env["PASSPHRASE"] = task.Task.Encryptionkey; task.Task.GetExtraSettings(args, env); psi.CreateNoWindow = true; psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; psi.FileName = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PythonPath); psi.RedirectStandardError = true; psi.RedirectStandardOutput = true; psi.RedirectStandardInput = false; psi.UseShellExecute = false; psi.WorkingDirectory = System.IO.Path.GetDirectoryName(psi.FileName); psi.Arguments = string.Join(" ", args.ToArray()); return psi; }
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"] = Duplicati.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(Duplicati_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(DuplicatiOperation.Backup, RunnerState.Started, task.Schedule.Name, "", 0, -1); } if (task.Task.IncludeSetup) { //Make a copy of the current database tf = new Duplicati.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.DuplicatiRunner.ShutdownWhileBackupInprogress); results = i.Backup(sourceFolders); } finally { if (tf != null) { tf.Dispose(); } if (ProgressEvent != null) { ProgressEvent(DuplicatiOperation.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(DuplicatiOperation.Restore, RunnerState.Started, task.Schedule.Name, "", 0, -1); } results = i.Restore(task.LocalPath.Split(System.IO.Path.PathSeparator)); } finally { if (ProgressEvent != null) { ProgressEvent(DuplicatiOperation.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.DuplicatiRunner.ApplicationExitLogMesssage; break; case System.Windows.Forms.CloseReason.TaskManagerClosing: parsedMessage = Strings.DuplicatiRunner.TaskManagerCloseMessage; break; case System.Windows.Forms.CloseReason.UserClosing: parsedMessage = Strings.DuplicatiRunner.UserClosingMessage; break; case System.Windows.Forms.CloseReason.WindowsShutDown: parsedMessage = Strings.DuplicatiRunner.WindowsShutdownMessage; break; default: parsedMessage = string.Format(Strings.DuplicatiRunner.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.DuplicatiRunner.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.DuplicatiRunner.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.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result; } if (!string.IsNullOrEmpty(task.Schedule.Task.KeepTime)) { m_lastPGProgress = 100; m_lastPGmessage = Strings.DuplicatiRunner.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.DuplicatiRunner.CleanupLogdataHeader + Environment.NewLine + tmpTask.Result; } if (task.Schedule.Task.KeepFull > 0 || !string.IsNullOrEmpty(task.Schedule.Task.KeepTime)) { ReinvokeLastProgressEvent(); } if (ProgressEvent != null) { ProgressEvent(DuplicatiOperation.Backup, RunnerState.Stopped, task.Schedule.Name, "", 100, -1); } } } catch (Exception ex) { results += Environment.NewLine + string.Format(Strings.DuplicatiRunner.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 == DuplicatiOutputParser.ErrorStatus) { r = RunnerResult.Error; } else if (l.ParsedStatus == DuplicatiOutputParser.OKStatus || l.ParsedStatus == DuplicatiOutputParser.NoChangedFiles) { r = RunnerResult.OK; } else if (l.ParsedStatus == DuplicatiOutputParser.PartialStatus) { r = RunnerResult.Partial; } else if (l.ParsedStatus == DuplicatiOutputParser.WarningStatus) { r = RunnerResult.Warning; } ResultEvent(r, parsedMessage, results); } } if (task.Schedule != null && !m_isAborted) { task.Schedule.ScheduledRunCompleted(); //Register as completed if not aborted } }
void m_form_Finished(object sender, System.ComponentModel.CancelEventArgs e) { Wizard_pages.WizardSettingsWrapper wrapper = new Duplicati.GUI.Wizard_pages.WizardSettingsWrapper(m_form.Settings); if (wrapper.PrimayAction == Duplicati.GUI.Wizard_pages.WizardSettingsWrapper.MainAction.Add || wrapper.PrimayAction == Duplicati.GUI.Wizard_pages.WizardSettingsWrapper.MainAction.Edit) { bool scheduleRun = wrapper.RunImmediately; bool autoScheduled = (wrapper.BackupTimeOffset < DateTime.Now) && !string.IsNullOrEmpty(wrapper.RepeatInterval); //Resume Duplicati if the backup is supposed to run if (scheduleRun || autoScheduled) { if (!AskToResumeIfPaused()) { e.Cancel = true; return; } } Schedule schedule; IDataFetcherWithRelations con = new DataFetcherNested(Program.DataConnection); if (wrapper.PrimayAction == Duplicati.GUI.Wizard_pages.WizardSettingsWrapper.MainAction.Add) { schedule = con.Add <Schedule>(); } else { schedule = con.GetObjectById <Schedule>(wrapper.ScheduleID); } wrapper.UpdateSchedule(schedule); lock (Program.MainLock) con.CommitAllRecursive(); schedule = Program.DataConnection.GetObjectById <Schedule>(schedule.ID); if (wrapper.UseEncryptionAsDefault) { ApplicationSettings appset = new ApplicationSettings(Program.DataConnection); appset.UseCommonPassword = true; appset.CommonPassword = wrapper.BackupPassword; appset.CommonPasswordEncryptionModule = wrapper.EncryptionModule; Program.DataConnection.Commit(Program.DataConnection.GetObjects <ApplicationSetting>()); } //If the user has selected that the backup should run now // and it is not run automatically, start it now if (scheduleRun && !autoScheduled) { Program.WorkThread.AddTask(new IncrementalBackupTask(schedule)); } } else if (m_form.CurrentPage is Wizard_pages.Restore.FinishedRestore) { if (!AskToResumeIfPaused()) { e.Cancel = true; return; } Schedule schedule = wrapper.DataConnection.GetObjectById <Schedule>(wrapper.ScheduleID); DateTime when = wrapper.RestoreTime; string target = wrapper.FullRestorePath; string restoreFilter = wrapper.RestoreFilter; if (when.Ticks == 0) { Program.WorkThread.AddTask(new RestoreTask(schedule, target, restoreFilter)); } else { Program.WorkThread.AddTask(new RestoreTask(schedule, target, restoreFilter, when)); } Program.DisplayHelper.ShowStatus(); } else if (m_form.CurrentPage is Wizard_pages.RunNow.RunNowFinished) { if (!AskToResumeIfPaused()) { e.Cancel = true; return; } Schedule schedule = wrapper.DataConnection.GetObjectById <Schedule>(wrapper.ScheduleID); if (wrapper.ForceFull) { Program.WorkThread.AddTask(new FullBackupTask(schedule)); } else { Program.WorkThread.AddTask(new IncrementalBackupTask(schedule)); } } else if (m_form.CurrentPage is Wizard_pages.Delete_backup.DeleteFinished) { Schedule schedule = wrapper.DataConnection.GetObjectById <Schedule>(wrapper.ScheduleID); if (Program.WorkThread.Active) { try { //TODO: It's not safe to access the values like this, //because the runner thread might interfere if (Program.WorkThread.CurrentTask.Schedule.ID == schedule.ID) { bool paused = Program.LiveControl.State == LiveControls.LiveControlState.Paused; Program.LiveControl.Pause(); if (MessageBox.Show(m_form.Dialog, Strings.WizardHandler.StopRunningBackupQuestion, Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) != DialogResult.Yes) { e.Cancel = true; if (!paused) { Program.LiveControl.Resume(); } return; } bool repaused = Program.LiveControl.State == LiveControls.LiveControlState.Paused; Program.LiveControl.Pause(); if (Program.WorkThread.CurrentTask.Schedule.ID == schedule.ID) { Program.Runner.Terminate(); } Cursor prevCursor = m_form.Dialog.Cursor; try { m_form.Dialog.Cursor = Cursors.WaitCursor; for (int i = 0; i < 10; i++) { if (Program.WorkThread.Active) { IDuplicityTask t = Program.WorkThread.CurrentTask; if (t != null && t.Schedule.ID == schedule.ID) { System.Threading.Thread.Sleep(1000); } else { break; } } else { break; } } } finally { try { m_form.Dialog.Cursor = prevCursor; } catch { } } if (Program.WorkThread.Active) { IDuplicityTask t = Program.WorkThread.CurrentTask; if (t == null && t.Schedule.ID == schedule.ID) { MessageBox.Show(m_form.Dialog, Strings.WizardHandler.UnableToStopBackupError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); e.Cancel = true; return; } } if (!paused || !repaused) { Program.LiveControl.Resume(); } } } catch (Exception ex) { MessageBox.Show(m_form.Dialog, string.Format(Strings.WizardHandler.StopBackupError, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); e.Cancel = true; return; } } //Prior to deleting we need to make sure all relations are loaded Queue <object> unvisited = new Queue <object>(); Dictionary <object, object> visited = new Dictionary <object, object>(); //Set up a transaction we can safely work on System.Data.LightDatamodel.DataFetcherNested con = new DataFetcherNested(Program.DataConnection); //Load the schedule in the transaction context object entryItem = con.GetObjectById <Schedule>(schedule.ID); unvisited.Enqueue(entryItem); visited[entryItem] = null; //Traverse the object relations while (unvisited.Count > 0) { object x = unvisited.Dequeue(); foreach (System.Reflection.PropertyInfo pi in x.GetType().GetProperties()) { if (pi.PropertyType != typeof(string) && (typeof(System.Data.LightDatamodel.IDataClass).IsAssignableFrom(pi.PropertyType) || typeof(System.Collections.IEnumerable).IsAssignableFrom(pi.PropertyType))) { try { object tmp = pi.GetValue(x, null); foreach (object i in tmp as System.Collections.IEnumerable ?? new object[] { tmp }) { if (i as IDataClass != null && !visited.ContainsKey(i)) { visited[i] = null; unvisited.Enqueue(i); } } } catch { //TODO: Perhaps log this? } } } } //Remove all entries visited foreach (IDataClass o in visited.Keys) { con.DeleteObject(o); } //TODO: The worker may schedule the task while we attempt to de-schedule it foreach (IDuplicityTask t in Program.WorkThread.CurrentTasks) { if (t != null && t is IncrementalBackupTask && ((IncrementalBackupTask)t).Schedule.ID == schedule.ID) { Program.WorkThread.RemoveTask(t); } } //Persist to database con.CommitAllRecursive(); //We have fiddled with the schedules Program.Scheduler.Reschedule(); } else if (m_form.CurrentPage is Wizard_pages.RestoreSetup.FinishedRestoreSetup) { MessageBox.Show(m_form as Form, Strings.WizardHandler.SetupRestoreSuccess, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); } }