diff --git a/Duplicati/GUI/DuplicatiRunner.cs b/Duplicati/GUI/DuplicatiRunner.cs
index 05b665148..c19c819d1 100644
--- a/Duplicati/GUI/DuplicatiRunner.cs
+++ b/Duplicati/GUI/DuplicatiRunner.cs
@@ -59,6 +59,7 @@ namespace Duplicati.GUI
string destination = task.GetConfiguration(options);
string results = "";
+ bool isAbortException = false;
try
{
@@ -224,7 +225,12 @@ namespace Duplicati.GUI
{
//TODO: Extract ex.Message and save it in seperate field in the database
if (ex is System.Threading.ThreadAbortException)
+ {
+ isAbortException = true;
System.Threading.Thread.ResetAbort();
+ }
+ else if (ex is Library.Main.LiveControl.ExecutionStoppedException)
+ isAbortException = true;
while (ex is System.Reflection.TargetInvocationException && ex.InnerException != null)
ex = ex.InnerException;
@@ -240,7 +246,7 @@ namespace Duplicati.GUI
try
{
- if (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup)
+ if (!isAbortException && (task.TaskType == DuplicityTaskType.FullBackup || task.TaskType == DuplicityTaskType.IncrementalBackup))
{
if (task.Schedule.Task.KeepFull > 0)
{
diff --git a/Duplicati/GUI/MainForm.cs b/Duplicati/GUI/MainForm.cs
index 6b8318fc7..23d1fc5df 100644
--- a/Duplicati/GUI/MainForm.cs
+++ b/Duplicati/GUI/MainForm.cs
@@ -179,6 +179,15 @@ namespace Duplicati.GUI
Program.LiveControl.Pause();
Program.Runner.Stop();
+
+ TrayIcon.Visible = false;
+ if (StatusDialog != null && StatusDialog.Visible)
+ StatusDialog.Close();
+ if (WizardDialog != null && WizardDialog.Visible)
+ WizardDialog.Close();
+
+ EnsureBackupIsTerminated();
+
Application.Exit();
}
@@ -305,5 +314,61 @@ namespace Duplicati.GUI
return false;
}
+
+ private void EnsureBackupIsTerminated()
+ {
+ if (Program.Runner != null && Program.WorkThread != null && Program.WorkThread.Active)
+ {
+ //Make sure no new items can enter the queue
+ if (Program.Scheduler != null)
+ Program.Scheduler.Terminate(true);
+
+ //We want no new items to enter the queue
+ Program.WorkThread.Terminate(false);
+
+ Program.Runner.Pause();
+ if (!Program.Runner.IsStopRequested)
+ Program.Runner.Stop();
+
+ //Wait 15 seconds to see if the stop works
+ for (int i = 0; i < 15; i++)
+ {
+ Program.WorkThread.Join(1000);
+ Application.DoEvents();
+ if (!Program.WorkThread.Active)
+ break;
+ }
+
+ while (Program.WorkThread.Active)
+ {
+ //Ask the user if we should abort
+ if (MessageBox.Show(Strings.Program.TerminateForExitQuestion, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
+ {
+ //Abort the thread
+ Program.Runner.Terminate();
+
+ //Give last 5 second chance to write the remaining data
+ int i = 5;
+ while (i > 0 && !Program.WorkThread.Join(1000))
+ {
+ //The Join call blocks the main thread, so let pending events through
+ Application.DoEvents();
+ i--;
+ }
+ break;
+ }
+
+ //Wait 18 * 10 seconds = 3 minutes before asking again
+ for (int i = 0; i < 18; i++)
+ {
+ Program.WorkThread.Join(1000 * 10);
+ Application.DoEvents();
+
+ if (!Program.WorkThread.Active)
+ break;
+ }
+ }
+ }
+ }
}
}
diff --git a/Duplicati/GUI/Program.cs b/Duplicati/GUI/Program.cs
index c80dc23af..5a978a783 100644
--- a/Duplicati/GUI/Program.cs
+++ b/Duplicati/GUI/Program.cs
@@ -207,38 +207,6 @@ namespace Duplicati.GUI
MessageBox.Show(string.Format(Strings.Program.SeriousError, ex.ToString()), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
- if (Runner != null && WorkThread != null && WorkThread.Active)
- {
- Runner.Pause();
- if (!Runner.IsStopRequested)
- Runner.Stop();
-
- //Wait 10 seconds to see if the stop works
- for (int i = 0; i < 10; i++)
- {
- System.Threading.Thread.Sleep(1000);
- if (!WorkThread.Active)
- break;
- }
-
- while (WorkThread.Active)
- {
- if (MessageBox.Show(Strings.Program.TerminateForExitQuestion, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
- {
- Runner.Terminate();
- System.Threading.Thread.Sleep(500);
- break;
- }
-
- //Wait 18 * 10 seconds = 3 minutes before asking again
- for (int i = 0; i < 18; i++)
- {
- System.Threading.Thread.Sleep(1000 * 10);
- if (!WorkThread.Active)
- break;
- }
- }
- }
if (Scheduler != null)
Scheduler.Terminate(true);
diff --git a/Duplicati/GUI/WizardHandler.cs b/Duplicati/GUI/WizardHandler.cs
index afd4d882c..8e406bca1 100644
--- a/Duplicati/GUI/WizardHandler.cs
+++ b/Duplicati/GUI/WizardHandler.cs
@@ -273,6 +273,11 @@ namespace Duplicati.GUI
(m_form as Form).ShowDialog();
}
+ public void Close()
+ {
+ if ((m_form as Form).Visible)
+ (m_form as Form).Close();
+ }
private bool AskToResumeIfPaused()
{
diff --git a/Duplicati/GUI/WorkerThread.cs b/Duplicati/GUI/WorkerThread.cs
index df9bce611..b61fbb0c7 100644
--- a/Duplicati/GUI/WorkerThread.cs
+++ b/Duplicati/GUI/WorkerThread.cs
@@ -295,5 +295,17 @@ namespace Duplicati.GUI
m_state = RunState.Paused;
m_event.Set();
}
+
+ ///
+ /// Waits the specified number of milliseconds for the thread to terminate
+ ///
+ /// The number of milliseconds to wait
+ /// True if the thread is terminated, false if a timeout occured
+ public bool Join(int millisecondTimeout)
+ {
+ if (m_thread != null)
+ return m_thread.Join(millisecondTimeout);
+ return true;
+ }
}
}
diff --git a/Duplicati/Library/Main/BackendWrapper.cs b/Duplicati/Library/Main/BackendWrapper.cs
index e43beedf6..6e3ffa029 100644
--- a/Duplicati/Library/Main/BackendWrapper.cs
+++ b/Duplicati/Library/Main/BackendWrapper.cs
@@ -574,6 +574,11 @@ namespace Duplicati.Library.Main
m_statistics.NumberOfRemoteCalls++;
return m_backend.List();
}
+ catch (System.Threading.ThreadAbortException tex)
+ {
+ lastEx = tex;
+ retries = 0;
+ }
catch (Exception ex)
{
lastEx = ex;
@@ -601,6 +606,11 @@ namespace Duplicati.Library.Main
m_backend.Delete(remote.Filename);
lastEx = null;
}
+ catch (System.Threading.ThreadAbortException tex)
+ {
+ lastEx = tex;
+ retries = 0;
+ }
catch (Exception ex)
{
lastEx = ex;
@@ -682,7 +692,7 @@ namespace Duplicati.Library.Main
{
try
{
- using(Library.Interface.IEncryption enc = DynamicLoader.EncryptionLoader.GetModule(remote.EncryptionMode, m_options.Passphrase, m_options.RawOptions))
+ using (Library.Interface.IEncryption enc = DynamicLoader.EncryptionLoader.GetModule(remote.EncryptionMode, m_options.Passphrase, m_options.RawOptions))
enc.Decrypt(tempfile, filename);
}
catch (Exception ex)
@@ -724,6 +734,11 @@ namespace Duplicati.Library.Main
}
}
}
+ catch (System.Threading.ThreadAbortException tex)
+ {
+ lastEx = tex;
+ retries = 0;
+ }
catch (Exception ex)
{
lastEx = ex;
@@ -821,9 +836,8 @@ namespace Duplicati.Library.Main
}
catch (System.Threading.ThreadAbortException tex)
{
- //Do not retry after we are aborted
lastEx = tex;
- break;
+ retries = 0;
}
catch (Exception ex)
{
diff --git a/Duplicati/Library/Main/Interface.cs b/Duplicati/Library/Main/Interface.cs
index 91ece37cd..29a62196c 100644
--- a/Duplicati/Library/Main/Interface.cs
+++ b/Duplicati/Library/Main/Interface.cs
@@ -197,8 +197,12 @@ namespace Duplicati.Library.Main
entries.Add(backupsets[backupsets.Count - 1]);
entries.AddRange(backupsets[backupsets.Count - 1].Incrementals);
+ //Check before we start the download
+ CheckLiveControl();
patches = FindPatches(backend, entries, tempfolder);
+ //Check before we start the download
+ CheckLiveControl();
Manifestfile latest = GetManifest(backend, backupsets[0]);
//Manifest version 1 does not support multiple folders
@@ -1136,7 +1140,6 @@ namespace Duplicati.Library.Main
{
m_progress += unitCost;
-
OperationProgress(this, DuplicatiOperation.Backup, (int)(m_progress * 100), -1, string.Format(Strings.Interface.StatusReadingManifest, be.Time.ToShortDateString() + " " + be.Time.ToShortTimeString()), "");
Manifestfile manifest = GetManifest(backend, be);
@@ -1157,6 +1160,9 @@ namespace Duplicati.Library.Main
string filename = System.IO.Path.Combine(tempfolder, "patch-" + patches.Count.ToString() + ".zip");
+ //Check just before we download stuff
+ CheckLiveControl();
+
using (new Logging.Timer("Get " + bes.Key.Filename))
backend.Get(bes.Key, filename, manifest.SignatureHashes == null ? null : manifest.SignatureHashes[bes.Key.Volumenumber - 1]);
diff --git a/Duplicati/Library/Main/LiveControl/ExecutionStoppedException.cs b/Duplicati/Library/Main/LiveControl/ExecutionStoppedException.cs
index f4e13166b..ff8347b5b 100644
--- a/Duplicati/Library/Main/LiveControl/ExecutionStoppedException.cs
+++ b/Duplicati/Library/Main/LiveControl/ExecutionStoppedException.cs
@@ -23,7 +23,7 @@ using System.Text;
namespace Duplicati.Library.Main.LiveControl
{
- class ExecutionStoppedException : Exception
+ public class ExecutionStoppedException : Exception
{
public ExecutionStoppedException()
: base(Strings.ExecutionStoppedException.DefaultMessage)
diff --git a/Duplicati/Library/Main/RSyncDir.cs b/Duplicati/Library/Main/RSyncDir.cs
index 42c347fe6..0d565d4f0 100644
--- a/Duplicati/Library/Main/RSyncDir.cs
+++ b/Duplicati/Library/Main/RSyncDir.cs
@@ -1558,17 +1558,26 @@ namespace Duplicati.Library.Main.RSync
{
BackupStatistics bs = m_stat as BackupStatistics;
- bs.DeletedFiles = m_deletedfiles.Count;
- bs.DeletedFolders = m_deletedfolders.Count;
- bs.ModifiedFiles = m_diffedfiles;
- bs.AddedFiles = m_addedfiles;
- bs.ExaminedFiles = m_examinedfiles;
- bs.SizeOfModifiedFiles = m_diffedfilessize;
- bs.SizeOfAddedFiles = m_addedfilessize;
- bs.SizeOfExaminedFiles = m_examinedfilesize;
+ if (m_deletedfiles != null)
+ bs.DeletedFiles = m_deletedfiles.Count;
+ if (m_deletedfolders != null)
+ bs.DeletedFolders = m_deletedfolders.Count;
+ if (m_diffedfiles != null)
+ bs.ModifiedFiles = m_diffedfiles;
+ if (m_addedfiles != null)
+ bs.AddedFiles = m_addedfiles;
+ if (m_examinedfiles != null)
+ bs.ExaminedFiles = m_examinedfiles;
+ if (m_diffedfilessize != null)
+ bs.SizeOfModifiedFiles = m_diffedfilessize;
+ if (m_addedfilessize != null)
+ bs.SizeOfAddedFiles = m_addedfilessize;
+ if (m_examinedfilesize != null)
+ bs.SizeOfExaminedFiles = m_examinedfilesize;
if (m_unproccesed != null && m_unproccesed.Files != null)
bs.UnprocessedFiles = m_unproccesed.Files.Count;
- bs.AddedFolders = m_newfolders.Count;
+ if (m_newfolders != null)
+ bs.AddedFolders = m_newfolders.Count;
}
if (m_snapshot != null)