Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/duplicati/duplicati.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Skovhede <kenneth@hexad.dk>2017-10-11 13:49:14 +0300
committerKenneth Skovhede <kenneth@hexad.dk>2017-10-11 13:49:14 +0300
commit6ad0fa649e837382fa7376ff2a223ee7ba4c0037 (patch)
tree7d197500b812dcb3aee0607f6ccf91a02be72fde /Duplicati
parentc7e0071d70f86b371e891f3f7f7584284bf1045c (diff)
Re-wrote the auto-updater to use process spawning instead of AppDomain loading to execute updates.
Diffstat (limited to 'Duplicati')
-rw-r--r--Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs2
-rw-r--r--Duplicati/Library/AutoUpdater/UpdaterManager.cs113
-rw-r--r--Duplicati/Library/Localization/MoLocalizationService.cs9
-rw-r--r--Duplicati/Server/Program.cs22
-rw-r--r--Duplicati/Server/UpdatePollThread.cs5
5 files changed, 142 insertions, 9 deletions
diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs
index d9a247204..79324e237 100644
--- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs
+++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs
@@ -67,7 +67,7 @@ namespace Duplicati.GUI.TrayIcon
List<string> args = new List<string>(_args);
Dictionary<string, string> options = Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args);
- if (Duplicati.Library.Utility.Utility.IsClientWindows && !Duplicati.Library.Utility.Utility.ParseBoolOption(options, DETACHED_PROCESS))
+ if (Duplicati.Library.Utility.Utility.IsClientWindows && (Duplicati.Library.AutoUpdater.UpdaterManager.IsRunningInUpdateEnvironment || !Duplicati.Library.Utility.Utility.ParseBoolOption(options, DETACHED_PROCESS)))
Duplicati.Library.Utility.Win32.AttachConsole(Duplicati.Library.Utility.Win32.ATTACH_PARENT_PROCESS);
foreach (string s in args)
diff --git a/Duplicati/Library/AutoUpdater/UpdaterManager.cs b/Duplicati/Library/AutoUpdater/UpdaterManager.cs
index 6328d461e..6f0857cf8 100644
--- a/Duplicati/Library/AutoUpdater/UpdaterManager.cs
+++ b/Duplicati/Library/AutoUpdater/UpdaterManager.cs
@@ -18,6 +18,8 @@
using System;
using System.Linq;
using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
namespace Duplicati.Library.AutoUpdater
{
@@ -34,6 +36,11 @@ namespace Duplicati.Library.AutoUpdater
public static class UpdaterManager
{
+ /// <summary>
+ /// The magic exit code that signals an update has been installed and that the app should restart
+ /// </summary>
+ public const int MAGIC_EXIT_CODE = 126;
+
private static readonly System.Security.Cryptography.RSACryptoServiceProvider SIGN_KEY = AutoUpdateSettings.SignKey;
private static readonly string[] MANIFEST_URLS = AutoUpdateSettings.URLs;
private static readonly string APPNAME = AutoUpdateSettings.AppName;
@@ -1002,8 +1009,114 @@ namespace Duplicati.Library.AutoUpdater
}
}
+ private static KeyValuePair<string, UpdateInfo> GetBestUpdateVersion(bool forcecheck = false)
+ {
+ if (forcecheck)
+ m_hasUpdateInstalled = null;
+
+ // Check if there are updates installed, otherwise use current
+ KeyValuePair<string, UpdateInfo> best = new KeyValuePair<string, UpdateInfo>(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, SelfVersion);
+ if (HasUpdateInstalled)
+ best = m_hasUpdateInstalled.Value;
+
+ if (INSTALLDIR != null && System.IO.File.Exists(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE)))
+ {
+ try
+ {
+ var current = System.IO.File.ReadAllText(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE)).Trim();
+ if (!string.IsNullOrWhiteSpace(current))
+ {
+ var targetfolder = System.IO.Path.Combine(INSTALLDIR, current);
+ var currentmanifest = ReadInstalledManifest(targetfolder);
+ if (currentmanifest != null && TryParseVersion(currentmanifest.Version) > TryParseVersion(best.Value.Version) && VerifyUnpackedFolder(targetfolder, currentmanifest))
+ best = new KeyValuePair<string, UpdateInfo>(targetfolder, currentmanifest);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (OnError != null)
+ OnError(ex);
+ }
+ }
+
+ return best;
+ }
+
+ public static bool IsRunningInUpdateEnvironment => !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(string.Format(BASEINSTALLDIR_ENVNAME_TEMPLATE, APPNAME)));
+
public static int RunFromMostRecent(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.CheckDuring)
{
+ return RunFromMostRecentSpawn(method, cmdargs, defaultstrategy);
+ }
+
+ public static int RunFromMostRecentSpawn(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.CheckDuring)
+ {
+ // If the update is disabled, go straight in
+ //if (DISABLE_UPDATE_DOMAIN)
+ // return RunMethod(method, cmdargs);
+
+ // If we are not the primary entry, just execute
+ if (IsRunningInUpdateEnvironment)
+ {
+ int r = 0;
+ WrapWithUpdater(defaultstrategy, () => {
+ r = RunMethod(method, cmdargs);
+ });
+
+ return r;
+ }
+
+ var args = Environment.CommandLine;
+ var app = Environment.GetCommandLineArgs().First();
+ args = args.Substring(app.Length);
+
+ if (!Path.IsPathRooted(app))
+ app = Path.Combine(InstalledBaseDir, app);
+
+ var executable = Path.GetFileName(app);
+
+ while (true)
+ {
+ var best = GetBestUpdateVersion(true);
+ var folder = best.Key;
+
+ var pi = new System.Diagnostics.ProcessStartInfo(Path.Combine(folder, executable), args)
+ {
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+ RedirectStandardOutput = true,
+ ErrorDialog = false,
+ };
+ pi.EnvironmentVariables.Clear();
+
+ var cur = Environment.GetEnvironmentVariables();
+ foreach (var e in cur.Keys)
+ if (e is string)
+ pi.EnvironmentVariables[(string)e] = cur[(string)e] as string;
+
+ pi.EnvironmentVariables[string.Format(BASEINSTALLDIR_ENVNAME_TEMPLATE, APPNAME)] = InstalledBaseDir;
+ pi.EnvironmentVariables["LOCALIZATION_FOLDER"] = InstalledBaseDir;
+
+ var proc = System.Diagnostics.Process.Start(pi);
+ var tasks = Task.WhenAll(
+ Console.OpenStandardInput().CopyToAsync(proc.StandardInput.BaseStream),
+ proc.StandardOutput.BaseStream.CopyToAsync(Console.OpenStandardOutput()),
+ proc.StandardError.BaseStream.CopyToAsync(Console.OpenStandardError())
+ );
+
+ proc.WaitForExit();
+ tasks.Wait(1000);
+
+ if (proc.ExitCode != MAGIC_EXIT_CODE)
+ return proc.ExitCode;
+ }
+
+ }
+
+ public static int RunFromMostRecentAppDomain(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.CheckDuring)
+ {
// If the update is disabled, go straight in
if (DISABLE_UPDATE_DOMAIN)
return RunMethod(method, cmdargs);
diff --git a/Duplicati/Library/Localization/MoLocalizationService.cs b/Duplicati/Library/Localization/MoLocalizationService.cs
index 2b94d6f1c..38667a471 100644
--- a/Duplicati/Library/Localization/MoLocalizationService.cs
+++ b/Duplicati/Library/Localization/MoLocalizationService.cs
@@ -40,13 +40,18 @@ namespace Duplicati.Library.Localization
/// </summary>
public const string LOCALIZATIONDIR_ENVNAME = "LOCALIZATION_FOLDER";
+ private static string LOCALIZATIONDIR_VALUE =
+ string.IsNullOrWhiteSpace(AppDomain.CurrentDomain.GetData(LOCALIZATIONDIR_ENVNAME) as string)
+ ? Environment.GetEnvironmentVariable(LOCALIZATIONDIR_ENVNAME)
+ : AppDomain.CurrentDomain.GetData(LOCALIZATIONDIR_ENVNAME) as string;
+
/// <summary>
/// Path to search for extra .mo files in
/// </summary>
public static string[] SearchPaths =
- string.IsNullOrWhiteSpace(AppDomain.CurrentDomain.GetData(LOCALIZATIONDIR_ENVNAME) as string)
+ string.IsNullOrWhiteSpace(LOCALIZATIONDIR_VALUE)
? new string[] { Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) }
- : (AppDomain.CurrentDomain.GetData(LOCALIZATIONDIR_ENVNAME) as string).Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
+ : (LOCALIZATIONDIR_VALUE).Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
/// <summary>
diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs
index ddc688ebe..28d116882 100644
--- a/Duplicati/Server/Program.cs
+++ b/Duplicati/Server/Program.cs
@@ -153,7 +153,7 @@ namespace Duplicati.Server
return Duplicati.Library.AutoUpdater.UpdaterManager.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args, Duplicati.Library.AutoUpdater.AutoUpdateStrategy.Never);
}
- public static void RealMain(string[] args)
+ public static int RealMain(string[] args)
{
//If we are on Windows, append the bundled "win-tools" programs to the search path
//We add it last, to allow the user to override with other versions
@@ -192,7 +192,7 @@ namespace Duplicati.Server
foreach(Library.Interface.ICommandLineArgument arg in SupportedCommands)
Console.WriteLine(Strings.Program.HelpDisplayFormat(arg.Name, arg.LongDescription));
- return;
+ return 0;
}
else
{
@@ -246,7 +246,7 @@ namespace Duplicati.Server
if (writeConsole)
{
Console.WriteLine(Strings.Program.StartupFailure(ex));
- return;
+ return 200;
}
throw new Exception(Strings.Program.StartupFailure(ex));
@@ -257,7 +257,7 @@ namespace Duplicati.Server
if (writeConsole)
{
Console.WriteLine(Strings.Program.AnotherInstanceDetected);
- return;
+ return 200;
}
throw new SingleInstance.MultipleInstanceException(Strings.Program.AnotherInstanceDetected);
@@ -323,7 +323,7 @@ namespace Duplicati.Server
try
{
PurgeTempFilesTimer = new System.Threading.Timer(purgeTempFilesCallback, null, TimeSpan.FromHours(1), TimeSpan.FromDays(1));
- }
+ }
catch (ArgumentOutOfRangeException)
{
//Bugfix for older Mono, slightly more resources used to avoid large values in the period field
@@ -399,7 +399,10 @@ namespace Duplicati.Server
{
System.Diagnostics.Trace.WriteLine(Strings.Program.SeriousError(mex.ToString()));
if (writeConsole)
+ {
Console.WriteLine(Strings.Program.SeriousError(mex.ToString()));
+ return 100;
+ }
else
throw mex;
}
@@ -407,7 +410,10 @@ namespace Duplicati.Server
{
System.Diagnostics.Trace.WriteLine(Strings.Program.SeriousError(ex.ToString()));
if (writeConsole)
+ {
Console.WriteLine(Strings.Program.SeriousError(ex.ToString()));
+ return 100;
+ }
else
throw new Exception(Strings.Program.SeriousError(ex.ToString()), ex);
}
@@ -434,8 +440,12 @@ namespace Duplicati.Server
if (LogHandler != null)
LogHandler.Dispose();
-
}
+
+ if (UpdatePoller != null && UpdatePoller.IsUpdateRequested)
+ return Library.AutoUpdater.UpdaterManager.MAGIC_EXIT_CODE;
+
+ return 0;
}
public static Database.Connection GetDatabaseConnection(Dictionary<string, string> commandlineOptions)
diff --git a/Duplicati/Server/UpdatePollThread.cs b/Duplicati/Server/UpdatePollThread.cs
index 4a66b284d..0c741aff5 100644
--- a/Duplicati/Server/UpdatePollThread.cs
+++ b/Duplicati/Server/UpdatePollThread.cs
@@ -35,6 +35,8 @@ namespace Duplicati.Server
private AutoResetEvent m_waitSignal;
private double m_downloadProgress;
+ public bool IsUpdateRequested { get; private set; } = false;
+
public UpdatePollerStates ThreadState { get; private set; }
public double DownloadProgess
{
@@ -81,7 +83,10 @@ namespace Duplicati.Server
public void ActivateUpdate()
{
if (Duplicati.Library.AutoUpdater.UpdaterManager.SetRunUpdate())
+ {
+ IsUpdateRequested = true;
Program.ApplicationExitEvent.Set();
+ }
}
public void Terminate()