diff options
22 files changed, 225 insertions, 189 deletions
diff --git a/BuildTools/AutoUpdateBuilder/Program.cs b/BuildTools/AutoUpdateBuilder/Program.cs index 2e7482058..2ddf77ec1 100644 --- a/BuildTools/AutoUpdateBuilder/Program.cs +++ b/BuildTools/AutoUpdateBuilder/Program.cs @@ -80,16 +80,14 @@ namespace AutoUpdateBuilder privkey.FromXmlString(sr.ReadToEnd());
}
- if (Duplicati.License.AutoUpdateSettings.SignKey == null || privkey.ToXmlString(false) != Duplicati.License.AutoUpdateSettings.SignKey.ToXmlString(false))
+ if (Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey == null || privkey.ToXmlString(false) != Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey.ToXmlString(false))
{
Console.WriteLine("The public key in the project is not the same as the public key from the file");
Console.WriteLine("Try setting the key to: ");
Console.WriteLine(privkey.ToXmlString(false));
return 5;
}
-
- var manager = new Duplicati.Library.AutoUpdater.UpdaterManager(null, null, Duplicati.License.AutoUpdateSettings.AppName);
-
+
Duplicati.Library.AutoUpdater.UpdateInfo updateInfo;
using (var fs = System.IO.File.OpenRead(manifestfile))
@@ -136,7 +134,7 @@ namespace AutoUpdateBuilder using (var tw = new System.IO.StreamWriter(fs))
new Newtonsoft.Json.JsonSerializer().Serialize(tw, updateInfo);
- manager.CreateUpdatePackage(privkey, inputfolder, outputfolder, tf);
+ Duplicati.Library.AutoUpdater.UpdaterManager.CreateUpdatePackage(privkey, inputfolder, outputfolder, tf);
}
return 0;
diff --git a/Duplicati/CommandLine/BackendTester/Program.cs b/Duplicati/CommandLine/BackendTester/Program.cs index 2a3fa94aa..4cef9a6c0 100644 --- a/Duplicati/CommandLine/BackendTester/Program.cs +++ b/Duplicati/CommandLine/BackendTester/Program.cs @@ -52,12 +52,7 @@ namespace Duplicati.CommandLine.BackendTester [STAThread]
public static int Main(string[] args)
{
- var updater = new Duplicati.Library.AutoUpdater.UpdaterManager(
- Duplicati.License.AutoUpdateSettings.URLs,
- Duplicati.License.AutoUpdateSettings.SignKey,
- Duplicati.License.AutoUpdateSettings.AppName);
-
- return updater.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args);
+ return Duplicati.Library.AutoUpdater.UpdaterManager.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args);
}
static void RealMain(string[] _args)
diff --git a/Duplicati/CommandLine/BackendTool/Program.cs b/Duplicati/CommandLine/BackendTool/Program.cs index 55d2f11ec..cac226fc8 100644 --- a/Duplicati/CommandLine/BackendTool/Program.cs +++ b/Duplicati/CommandLine/BackendTool/Program.cs @@ -32,12 +32,7 @@ namespace Duplicati.CommandLine.BackendTool [STAThread]
public static int Main(string[] args)
{
- var updater = new Duplicati.Library.AutoUpdater.UpdaterManager(
- Duplicati.License.AutoUpdateSettings.URLs,
- Duplicati.License.AutoUpdateSettings.SignKey,
- Duplicati.License.AutoUpdateSettings.AppName);
-
- return updater.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args);
+ return Duplicati.Library.AutoUpdater.UpdaterManager.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args);
}
static int RealMain(string[] _args)
diff --git a/Duplicati/CommandLine/Program.cs b/Duplicati/CommandLine/Program.cs index 178b2345d..f3abee95c 100644 --- a/Duplicati/CommandLine/Program.cs +++ b/Duplicati/CommandLine/Program.cs @@ -77,12 +77,7 @@ namespace Duplicati.CommandLine [STAThread]
public static int Main(string[] args)
{
- var updater = new Duplicati.Library.AutoUpdater.UpdaterManager(
- Duplicati.License.AutoUpdateSettings.URLs,
- Duplicati.License.AutoUpdateSettings.SignKey,
- Duplicati.License.AutoUpdateSettings.AppName);
-
- return updater.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args);
+ return Duplicati.Library.AutoUpdater.UpdaterManager.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args);
}
static int RealMain(string[] args)
diff --git a/Duplicati/GUI/Duplicati.GUI.MacTrayIcon/CocoaRunner.cs b/Duplicati/GUI/Duplicati.GUI.MacTrayIcon/CocoaRunner.cs index 5946d80e6..d76ae4d6d 100644 --- a/Duplicati/GUI/Duplicati.GUI.MacTrayIcon/CocoaRunner.cs +++ b/Duplicati/GUI/Duplicati.GUI.MacTrayIcon/CocoaRunner.cs @@ -125,10 +125,20 @@ namespace Duplicati.GUI.MacTrayIcon // We need to keep the items around, otherwise the GC will destroy them and crash the app
private List<Duplicati.GUI.TrayIcon.IMenuItem> m_keeper = new List<Duplicati.GUI.TrayIcon.IMenuItem>();
- public override void Init (string[] args)
+ private class TerminateException : Exception
+ {
+ }
+
+ public override void Init(string[] args)
{
NSApplication.Init();
- NSApplication.Main(args);
+ try
+ {
+ NSApplication.Main(args);
+ }
+ catch (TerminateException)
+ {
+ }
}
public void AwakeFromNib(AppDelegate caller)
@@ -213,7 +223,11 @@ namespace Duplicati.GUI.MacTrayIcon protected override void Exit ()
{
- NSApplication.SharedApplication.Terminate(m_appDelegate);
+ //NSApplication.SharedApplication.Terminate(m_appDelegate);
+
+ // Not the nicest way, but cannot figure out
+ // how to stop the message loop without killing the application otherwise
+ throw new TerminateException();
}
protected override void SetMenu(System.Collections.Generic.IEnumerable<Duplicati.GUI.TrayIcon.IMenuItem> items)
diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs index 23dcec96c..531849518 100644 --- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Program.cs @@ -66,13 +66,7 @@ namespace Duplicati.GUI.TrayIcon public static int Main(string[] args)
{
Duplicati.Library.AutoUpdater.UpdaterManager.RequiresRespawn = true;
-
- var updater = new Duplicati.Library.AutoUpdater.UpdaterManager(
- Duplicati.License.AutoUpdateSettings.URLs,
- Duplicati.License.AutoUpdateSettings.SignKey,
- Duplicati.License.AutoUpdateSettings.AppName);
-
- return updater.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args, Duplicati.Library.AutoUpdater.AutoUpdateStrategy.Never);
+ return Duplicati.Library.AutoUpdater.UpdaterManager.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args, Duplicati.Library.AutoUpdater.AutoUpdateStrategy.Never);
}
public static void RealMain(string[] _args)
diff --git a/Duplicati/License/AutoUpdateAppName.txt b/Duplicati/Library/AutoUpdater/AutoUpdateAppName.txt index bbae053aa..bbae053aa 100644 --- a/Duplicati/License/AutoUpdateAppName.txt +++ b/Duplicati/Library/AutoUpdater/AutoUpdateAppName.txt diff --git a/Duplicati/Library/AutoUpdater/AutoUpdateFolderReadme.txt b/Duplicati/Library/AutoUpdater/AutoUpdateFolderReadme.txt new file mode 100644 index 000000000..fbab8836c --- /dev/null +++ b/Duplicati/Library/AutoUpdater/AutoUpdateFolderReadme.txt @@ -0,0 +1,15 @@ +This folder is used to store updates.
+
+Each folder is checked before launch to ensure the integrity of the application.
+
+DO NOT MODIFY THE FOLDERS!
+
+This means:
+DO NOT CHANGE ANY FILES!
+DO NOT DELETE ANY FILES!
+DO NOT ADD ANY FILES!
+
+If anything is changed, the updates will be rejected, and a previous version is used.
+
+If you need to modify something, use the folder where the application is installed.
+
diff --git a/Duplicati/License/AutoUpdateSettings.cs b/Duplicati/Library/AutoUpdater/AutoUpdateSettings.cs index e20b6dc98..7c8fb82c8 100644 --- a/Duplicati/License/AutoUpdateSettings.cs +++ b/Duplicati/Library/AutoUpdater/AutoUpdateSettings.cs @@ -18,7 +18,7 @@ using System;
using System.Collections.Generic;
-namespace Duplicati.License
+namespace Duplicati.Library.AutoUpdater
{
public static class AutoUpdateSettings
{
@@ -26,6 +26,7 @@ namespace Duplicati.License private const string APP_NAME = "AutoUpdateAppName.txt";
private const string UPDATE_URL = "AutoUpdateURL.txt";
private const string UPDATE_KEY = "AutoUpdateSignKey.txt";
+ private const string UPDATE_README = "AutoUpdateFolderReadme.txt";
private const string UPDATEURL_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_URLS";
@@ -35,6 +36,7 @@ namespace Duplicati.License ReadResourceText(APP_NAME);
ReadResourceText(UPDATE_URL);
ReadResourceText(UPDATE_KEY);
+ ReadResourceText(UPDATE_README);
}
private static string ReadResourceText(string name)
@@ -86,6 +88,11 @@ namespace Duplicati.License get { return ReadResourceText(APP_NAME); }
}
+ public static string UpdateFolderReadme
+ {
+ get { return ReadResourceText(UPDATE_README); }
+ }
+
public static System.Security.Cryptography.RSACryptoServiceProvider SignKey
{
get
diff --git a/Duplicati/License/AutoUpdateSignKey.txt b/Duplicati/Library/AutoUpdater/AutoUpdateSignKey.txt index 01b1eda73..01b1eda73 100644 --- a/Duplicati/License/AutoUpdateSignKey.txt +++ b/Duplicati/Library/AutoUpdater/AutoUpdateSignKey.txt diff --git a/Duplicati/License/AutoUpdateURL.txt b/Duplicati/Library/AutoUpdater/AutoUpdateURL.txt index 5623cac9a..5623cac9a 100644 --- a/Duplicati/License/AutoUpdateURL.txt +++ b/Duplicati/Library/AutoUpdater/AutoUpdateURL.txt diff --git a/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj b/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj index 7907ce54b..be472a95a 100644 --- a/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj +++ b/Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj @@ -42,6 +42,7 @@ <Compile Include="UpdateInfo.cs" /> <Compile Include="FileEntry.cs" /> <Compile Include="SignatureReadingStream.cs" /> + <Compile Include="AutoUpdateSettings.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> @@ -58,4 +59,10 @@ <Name>Duplicati.Library.Interface</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="AutoUpdateAppName.txt" /> + <EmbeddedResource Include="AutoUpdateSignKey.txt" /> + <EmbeddedResource Include="AutoUpdateURL.txt" /> + <EmbeddedResource Include="AutoUpdateFolderReadme.txt" /> + </ItemGroup> </Project>
\ No newline at end of file diff --git a/Duplicati/Library/AutoUpdater/UpdaterManager.cs b/Duplicati/Library/AutoUpdater/UpdaterManager.cs index bc1a61f77..51e1bb469 100644 --- a/Duplicati/Library/AutoUpdater/UpdaterManager.cs +++ b/Duplicati/Library/AutoUpdater/UpdaterManager.cs @@ -32,26 +32,33 @@ namespace Duplicati.Library.AutoUpdater Never
}
- public class UpdaterManager
+ public static class UpdaterManager
{
- private System.Security.Cryptography.RSACryptoServiceProvider m_key;
- private string[] m_urls;
- private string m_appname;
- private string m_installdir;
+ 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;
+
+ private static readonly string INSTALLDIR;
+
+ private static readonly string INSTALLED_BASE_DIR = string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME))) ?
+ System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)
+ : System.Environment.GetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME));
public static bool RequiresRespawn { get; set; }
- private KeyValuePair<string, UpdateInfo>? m_hasUpdateInstalled;
+ private static KeyValuePair<string, UpdateInfo>? m_hasUpdateInstalled;
- private UpdateInfo m_selfVersion;
+ private static readonly UpdateInfo SelfVersion;
- public event Action<Exception> OnError;
+ public static event Action<Exception> OnError;
private const string DATETIME_FORMAT = "yyyymmddhhMMss";
private const string INSTALLDIR_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_INSTALL_ROOT";
private const string RUN_UPDATED_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_LOAD_UPDATE";
private const string SLEEP_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_SLEEP";
private const string UPDATE_MANIFEST_FILENAME = "autoupdate.manifest";
+ private const string README_FILE = "README.txt";
+ private const string CURRENT_FILE = "current";
public const string AUTO_UPDATE_OPTION = "auto-update-strategy";
@@ -59,43 +66,59 @@ namespace Duplicati.Library.AutoUpdater /// Gets the original directory that this application was installed into
/// </summary>
/// <value>The original directory that this application was installed into</value>
- public string InstalledBaseDir
+ public static string InstalledBaseDir { get { return INSTALLED_BASE_DIR; } }
+
+ static UpdaterManager()
{
- get
+ string installdir = null;
+ var attempts = new string[] {
+ System.IO.Path.Combine(InstalledBaseDir, "updates"),
+ System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), APPNAME, "updates"),
+ System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), APPNAME, "updates"),
+ System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME, "updates"),
+ };
+
+ foreach(var p in attempts)
+ if (TestDirectoryIsWriteable(p))
+ {
+ installdir = p;
+ break;
+ }
+
+ INSTALLDIR = installdir;
+
+ if (INSTALLDIR != null)
{
- var s = System.Environment.GetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, m_appname));
- if (string.IsNullOrWhiteSpace(s))
- return System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
- else
- return s;
+ if (!System.IO.File.Exists(System.IO.Path.Combine(INSTALLDIR, README_FILE)))
+ System.IO.File.WriteAllText(System.IO.Path.Combine(INSTALLDIR, README_FILE), AutoUpdateSettings.UpdateFolderReadme);
}
- }
-
- public UpdaterManager(string[] urls, System.Security.Cryptography.RSACryptoServiceProvider key, string appname, string installdir = null)
- {
- m_key = key;
- m_urls = urls;
- m_appname = appname;
- m_installdir = installdir;
- if (string.IsNullOrWhiteSpace(m_installdir))
+
+ UpdateInfo selfVersion = null;
+ try
+ {
+ selfVersion = ReadInstalledManifest(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location));
+ }
+ catch
{
- var attempts = new string[] {
- System.IO.Path.Combine(InstalledBaseDir, "updates"),
- System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), m_appname, "updates"),
- System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), m_appname, "updates"),
- System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), m_appname, "updates"),
+ }
+
+ if (selfVersion == null)
+ selfVersion = new UpdateInfo() {
+ Displayname = "Current",
+ Version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
+ ReleaseTime = new DateTime(0),
+ ReleaseType =
+#if DEBUG
+ "Debug"
+#else
+ "Nightly"
+#endif
};
- foreach(var p in attempts)
- if (TestDirectoryIsWriteable(p))
- {
- m_installdir = p;
- break;
- }
- }
+ SelfVersion = selfVersion;
}
- private Version TryParseVersion(string str)
+ private static Version TryParseVersion(string str)
{
Version v;
if (Version.TryParse(str, out v))
@@ -104,13 +127,13 @@ namespace Duplicati.Library.AutoUpdater return new Version(0, 0);
}
- public bool HasUpdateInstalled
+ public static bool HasUpdateInstalled
{
get
{
if (!m_hasUpdateInstalled.HasValue)
{
- var selfversion = TryParseVersion(this.SelfVersion.Version);
+ var selfversion = TryParseVersion(SelfVersion.Version);
m_hasUpdateInstalled =
(from n in FindInstalledVersions()
@@ -126,39 +149,7 @@ namespace Duplicati.Library.AutoUpdater }
}
- private UpdateInfo SelfVersion
- {
- get
- {
- if (m_selfVersion == null)
- {
- try
- {
- m_selfVersion = ReadInstalledManifest(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location));
- }
- catch
- {
- }
-
- if (m_selfVersion == null)
- m_selfVersion = new UpdateInfo() {
- Displayname = "Current",
- Version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
- ReleaseTime = new DateTime(0),
- ReleaseType =
-#if DEBUG
- "Debug"
-#else
- "Nightly"
-#endif
- };
- }
-
- return m_selfVersion;
- }
- }
-
- private bool TestDirectoryIsWriteable(string path)
+ private static bool TestDirectoryIsWriteable(string path)
{
var p2 = System.IO.Path.Combine(path, "test-" + DateTime.UtcNow.ToString(DATETIME_FORMAT));
var probe = System.IO.Directory.Exists(path) ? p2 : path;
@@ -180,9 +171,9 @@ namespace Duplicati.Library.AutoUpdater return false;
}
- public UpdateInfo CheckForUpdate()
+ public static UpdateInfo CheckForUpdate()
{
- foreach(var url in m_urls)
+ foreach(var url in MANIFEST_URLS)
{
try
{
@@ -192,7 +183,7 @@ namespace Duplicati.Library.AutoUpdater wc.DownloadFile(url, tmpfile);
using(var fs = System.IO.File.OpenRead(tmpfile))
- using(var ss = new SignatureReadingStream(fs, m_key))
+ using(var ss = new SignatureReadingStream(fs, SIGN_KEY))
using(var tr = new System.IO.StreamReader(ss))
using(var jr = new Newtonsoft.Json.JsonTextReader(tr))
{
@@ -218,7 +209,7 @@ namespace Duplicati.Library.AutoUpdater return null;
}
- private UpdateInfo ReadInstalledManifest(string folder)
+ private static UpdateInfo ReadInstalledManifest(string folder)
{
var manifest = System.IO.Path.Combine(folder, UPDATE_MANIFEST_FILENAME);
if (System.IO.File.Exists(manifest))
@@ -226,7 +217,7 @@ namespace Duplicati.Library.AutoUpdater try
{
using(var fs = System.IO.File.OpenRead(manifest))
- using(var ss = new SignatureReadingStream(fs, m_key))
+ using(var ss = new SignatureReadingStream(fs, SIGN_KEY))
using(var tr = new System.IO.StreamReader(ss))
using(var jr = new Newtonsoft.Json.JsonTextReader(tr))
return new Newtonsoft.Json.JsonSerializer().Deserialize<UpdateInfo>(jr);
@@ -241,21 +232,25 @@ namespace Duplicati.Library.AutoUpdater return null;
}
- public IEnumerable<KeyValuePair<string, UpdateInfo>> FindInstalledVersions()
+ public static IEnumerable<KeyValuePair<string, UpdateInfo>> FindInstalledVersions()
{
var res = new List<KeyValuePair<string, UpdateInfo>>();
- foreach(var folder in System.IO.Directory.GetDirectories(m_installdir))
- {
- var r = ReadInstalledManifest(folder);
- if (r != null)
- res.Add(new KeyValuePair<string, UpdateInfo>(folder, r));
- }
+ if (INSTALLDIR != null)
+ foreach(var folder in System.IO.Directory.GetDirectories(INSTALLDIR))
+ {
+ var r = ReadInstalledManifest(folder);
+ if (r != null)
+ res.Add(new KeyValuePair<string, UpdateInfo>(folder, r));
+ }
return res;
}
- public bool DownloadAndUnpackUpdate(UpdateInfo version)
+ public static bool DownloadAndUnpackUpdate(UpdateInfo version)
{
+ if (INSTALLDIR == null)
+ return false;
+
using(var tempfile = new Library.Utility.TempFile())
{
foreach(var url in version.RemoteURLS)
@@ -305,7 +300,8 @@ namespace Duplicati.Library.AutoUpdater if (VerifyUnpackedFolder(tempfolder, version))
{
- var targetfolder = System.IO.Path.Combine(m_installdir, version.ReleaseTime.ToString(DATETIME_FORMAT));
+ var versionstring = TryParseVersion(version.Version).ToString();
+ var targetfolder = System.IO.Path.Combine(INSTALLDIR, versionstring);
if (System.IO.Directory.Exists(targetfolder))
System.IO.Directory.Delete(targetfolder, true);
@@ -332,7 +328,8 @@ namespace Duplicati.Library.AutoUpdater // Verification will kick in when we list the installed updates
//VerifyUnpackedFolder(targetfolder, version);
-
+ System.IO.File.WriteAllText(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE), versionstring);
+
m_hasUpdateInstalled = null;
return true;
}
@@ -353,7 +350,7 @@ namespace Duplicati.Library.AutoUpdater return false;
}
- public bool VerifyUnpackedFolder(string folder, UpdateInfo version = null)
+ public static bool VerifyUnpackedFolder(string folder, UpdateInfo version = null)
{
try
{
@@ -365,7 +362,7 @@ namespace Duplicati.Library.AutoUpdater using(var fs = System.IO.File.OpenRead(System.IO.Path.Combine(folder, UPDATE_MANIFEST_FILENAME)))
{
- using(var ss = new SignatureReadingStream(fs, m_key))
+ using(var ss = new SignatureReadingStream(fs, SIGN_KEY))
using(var tr = new System.IO.StreamReader(ss))
using(var jr = new Newtonsoft.Json.JsonTextReader(tr))
update = new Newtonsoft.Json.JsonSerializer().Deserialize<UpdateInfo>(jr);
@@ -458,18 +455,18 @@ namespace Duplicati.Library.AutoUpdater return false;
}
- public bool SetRunUpdate()
+ public static bool SetRunUpdate()
{
if (HasUpdateInstalled)
{
- Environment.SetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, m_appname), m_hasUpdateInstalled.Value.Key);
- return !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, m_appname)));
+ Environment.SetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, APPNAME), m_hasUpdateInstalled.Value.Key);
+ return !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, APPNAME)));
}
return false;
}
- public void CreateUpdatePackage(System.Security.Cryptography.RSACryptoServiceProvider key, string inputfolder, string outputfolder, string manifest = null)
+ public static void CreateUpdatePackage(System.Security.Cryptography.RSACryptoServiceProvider key, string inputfolder, string outputfolder, string manifest = null)
{
// Read the existing manifest
@@ -602,7 +599,7 @@ namespace Duplicati.Library.AutoUpdater new Newtonsoft.Json.JsonSerializer().Serialize(sw, remoteManifest);
sw.Flush();
- using (var fs = System.IO.File.OpenWrite(tf))
+ using (var fs = System.IO.File.Create(tf))
SignatureReadingStream.CreateSignedStream(ms, fs, key);
}
@@ -611,7 +608,7 @@ namespace Duplicati.Library.AutoUpdater }
- private int RunMethod(System.Reflection.MethodInfo method, string[] args)
+ private static int RunMethod(System.Reflection.MethodInfo method, string[] args)
{
try
{
@@ -630,17 +627,17 @@ namespace Duplicati.Library.AutoUpdater }
}
- public int RunFromMostRecent(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.InstallDuring)
+ public static int RunFromMostRecent(System.Reflection.MethodInfo method, string[] cmdargs, AutoUpdateStrategy defaultstrategy = AutoUpdateStrategy.InstallDuring)
{
// If we are not the primary domain, just execute
if (!AppDomain.CurrentDomain.IsDefaultAppDomain())
return RunMethod(method, cmdargs);
// If we are a re-launch, wait briefly for the other process to exit
- var sleepmarker = System.Environment.GetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, m_appname));
+ var sleepmarker = System.Environment.GetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME));
if (!string.IsNullOrWhiteSpace(sleepmarker))
{
- System.Environment.SetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, m_appname), null);
+ System.Environment.SetEnvironmentVariable(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME), null);
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(15));
}
@@ -759,8 +756,31 @@ namespace Duplicati.Library.AutoUpdater }
// Check if there are updates installed, otherwise use current
- var best = HasUpdateInstalled ? m_hasUpdateInstalled.Value : new KeyValuePair<string, UpdateInfo>(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, SelfVersion);
- Environment.SetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, m_appname), InstalledBaseDir);
+ 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 && VerifyUnpackedFolder(targetfolder, currentmanifest))
+ best = new KeyValuePair<string, UpdateInfo>(targetfolder, currentmanifest);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (OnError != null)
+ OnError(ex);
+ }
+ }
+
+ Environment.SetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME), InstalledBaseDir);
var folder = best.Key;
@@ -770,8 +790,6 @@ namespace Duplicati.Library.AutoUpdater //
// This allows more or less seamless updates
//
- // The client is responsible for checking for updates and starting the downloads
- //
int result = 0;
while (!string.IsNullOrWhiteSpace(folder) && System.IO.Directory.Exists(folder))
@@ -794,10 +812,10 @@ namespace Duplicati.Library.AutoUpdater Console.WriteLine("Appdomain unload error: {0}", ex);
}
- folder = Environment.GetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, m_appname));
+ folder = Environment.GetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, APPNAME));
if (!string.IsNullOrWhiteSpace(folder))
{
- Environment.SetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, m_appname), null);
+ Environment.SetEnvironmentVariable(string.Format(RUN_UPDATED_ENVNAME_TEMPLATE, APPNAME), null);
if (!VerifyUnpackedFolder(folder))
folder = prevfolder; //Go back and run the previous version
else if (RequiresRespawn)
@@ -814,17 +832,31 @@ namespace Duplicati.Library.AutoUpdater if (!System.IO.Path.IsPathRooted(app))
app = System.IO.Path.Combine(InstalledBaseDir, app);
+ if (Duplicati.Library.Utility.Utility.IsClientOSX && System.Reflection.Assembly.GetEntryAssembly().GetName().Name == "Duplicati.GUI.MacTrayIcon")
+ {
+ // On OSX, we re-launch the app with a delay
+ var np = app;
+ while(!string.IsNullOrWhiteSpace(np) && !np.EndsWith(".app", StringComparison.InvariantCultureIgnoreCase))
+ np = System.IO.Path.GetDirectoryName(np);
+
+ if (!string.IsNullOrWhiteSpace(np))
+ {
+ app = "bash";
+ args = "-c 'sleep 10; open \"" + np + "\" " + args + "'";
+ }
+ }
+
// Re-launch but give the OS a little time to fully unload all open handles, etc.
var si = new System.Diagnostics.ProcessStartInfo(app, args);
- si.EnvironmentVariables.Add(string.Format(SLEEP_ENVNAME_TEMPLATE, m_appname), "1");
- si.UseShellExecute = false;
+ if (app != "bash")
+ {
+ si.UseShellExecute = false;
+ si.EnvironmentVariables.Add(string.Format(SLEEP_ENVNAME_TEMPLATE, APPNAME), "1");
+ }
- var pr = System.Diagnostics.Process.Start(si);
+ System.Diagnostics.Process.Start(si);
- if (pr.WaitForExit((int)TimeSpan.FromSeconds(5).TotalMilliseconds))
- folder = prevfolder;
- else
- return 0;
+ return 0;
}
catch (Exception ex)
{
diff --git a/Duplicati/Library/Main/Duplicati.Library.Main.csproj b/Duplicati/Library/Main/Duplicati.Library.Main.csproj index 5b622d369..0c4d561bc 100644 --- a/Duplicati/Library/Main/Duplicati.Library.Main.csproj +++ b/Duplicati/Library/Main/Duplicati.Library.Main.csproj @@ -149,6 +149,10 @@ <Project>{B68F2214-951F-4F78-8488-66E1ED3F50BF}</Project>
<Name>Duplicati.Library.Localization</Name>
</ProjectReference>
+ <ProjectReference Include="..\AutoUpdater\Duplicati.Library.AutoUpdater.csproj">
+ <Project>{7E119745-1F62-43F0-936C-F312A1912C0B}</Project>
+ <Name>Duplicati.Library.AutoUpdater</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
diff --git a/Duplicati/Library/Main/Options.cs b/Duplicati/Library/Main/Options.cs index 8f9964a81..02bfd3de1 100644 --- a/Duplicati/Library/Main/Options.cs +++ b/Duplicati/Library/Main/Options.cs @@ -172,7 +172,7 @@ namespace Duplicati.Library.Main return r.ToArray();
}
- private static readonly string DEFAULT_COMPRESSED_EXTENSION_FILE = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "default_compressed_extensions.txt");
+ private static readonly string DEFAULT_COMPRESSED_EXTENSION_FILE = System.IO.Path.Combine(Duplicati.Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "default_compressed_extensions.txt");
/// <summary>
/// Lock that protects the options collection
diff --git a/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj b/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj index c345f0446..e7f3e0bc5 100644 --- a/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj +++ b/Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj @@ -99,6 +99,10 @@ <Project>{C5899F45-B0FF-483C-9D38-24A9FCAAB237}</Project>
<Name>Duplicati.Library.Interface</Name>
</ProjectReference>
+ <ProjectReference Include="..\AutoUpdater\Duplicati.Library.AutoUpdater.csproj">
+ <Project>{7E119745-1F62-43F0-936C-F312A1912C0B}</Project>
+ <Name>Duplicati.Library.AutoUpdater</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
diff --git a/Duplicati/Library/Snapshots/LinuxSnapshot.cs b/Duplicati/Library/Snapshots/LinuxSnapshot.cs index ebde7ca7a..9f5c7765b 100644 --- a/Duplicati/Library/Snapshots/LinuxSnapshot.cs +++ b/Duplicati/Library/Snapshots/LinuxSnapshot.cs @@ -132,7 +132,7 @@ namespace Duplicati.Library.Snapshots /// <returns>A string with the combined output of the stdout and stderr</returns>
private static string ExecuteCommand(string program, string commandline, int expectedExitCode)
{
- program = System.IO.Path.Combine(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "lvm-scripts"), program);
+ program = System.IO.Path.Combine(System.IO.Path.Combine(Duplicati.Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "lvm-scripts"), program);
System.Diagnostics.ProcessStartInfo inf = new System.Diagnostics.ProcessStartInfo(program, commandline);
inf.CreateNoWindow = true;
inf.RedirectStandardError = true;
diff --git a/Duplicati/License/Duplicati.License.csproj b/Duplicati/License/Duplicati.License.csproj index bc0707138..e47d886dc 100644 --- a/Duplicati/License/Duplicati.License.csproj +++ b/Duplicati/License/Duplicati.License.csproj @@ -216,7 +216,6 @@ <Compile Include="LicenseReader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VersionNumbers.cs" />
- <Compile Include="AutoUpdateSettings.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Duplicati.snk" />
@@ -235,8 +234,5 @@ </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="VersionTag.txt" />
- <EmbeddedResource Include="AutoUpdateURL.txt" />
- <EmbeddedResource Include="AutoUpdateAppName.txt" />
- <EmbeddedResource Include="AutoUpdateSignKey.txt" />
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs index f85d09532..d3492d6ad 100644 --- a/Duplicati/Server/Program.cs +++ b/Duplicati/Server/Program.cs @@ -8,24 +8,19 @@ namespace Duplicati.Server public class Program
{
/// <summary>
- /// The name of the application, change this to re-brand it
- /// </summary>
- public const string ApplicationName = "Duplicati";
-
- /// <summary>
/// The path to the directory that contains the main executable
/// </summary>
- public static readonly string StartupPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
+ public static readonly string StartupPath = Duplicati.Library.AutoUpdater.UpdaterManager.InstalledBaseDir;
/// <summary>
/// The name of the environment variable that holds the path to the data folder used by Duplicati
/// </summary>
- public static readonly string DATAFOLDER_ENV_NAME = ApplicationName.ToUpper() + "_HOME";
+ public static readonly string DATAFOLDER_ENV_NAME = Duplicati.Library.AutoUpdater.AutoUpdateSettings.AppName.ToUpper() + "_HOME";
/// <summary>
/// The environment variable that holdes the database key used to encrypt the SQLite database
/// </summary>
- public static readonly string DB_KEY_ENV_NAME = ApplicationName.ToUpper() + "_DB_KEY";
+ public static readonly string DB_KEY_ENV_NAME = Duplicati.Library.AutoUpdater.AutoUpdateSettings.AppName.ToUpper() + "_DB_KEY";
/// <summary>
/// Gets the folder where Duplicati data is stored
@@ -83,11 +78,6 @@ namespace Duplicati.Server public static WebServer.Server WebServer;
/// <summary>
- /// The update manager instance
- /// </summary>
- public static Library.AutoUpdater.UpdaterManager UpdateManager;
-
- /// <summary>
/// The update poll thread.
/// </summary>
public static UpdatePollThread UpdatePoller;
@@ -142,12 +132,7 @@ namespace Duplicati.Server [STAThread]
public static int Main(string[] args)
{
- var updater = new Duplicati.Library.AutoUpdater.UpdaterManager(
- Duplicati.License.AutoUpdateSettings.URLs,
- Duplicati.License.AutoUpdateSettings.SignKey,
- Duplicati.License.AutoUpdateSettings.AppName);
-
- return updater.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args);
+ return Duplicati.Library.AutoUpdater.UpdaterManager.RunFromMostRecent(typeof(Program).GetMethod("RealMain"), args, Duplicati.Library.AutoUpdater.AutoUpdateStrategy.Never);
}
public static void RealMain(string[] args)
@@ -188,7 +173,7 @@ namespace Duplicati.Server //If you change the key, please note that you need to supply the same
// key when restoring the setup, as the setup being backed up will
// be encrypted as well.
- Environment.SetEnvironmentVariable(DB_KEY_ENV_NAME, ApplicationName + "_Key_42");
+ Environment.SetEnvironmentVariable(DB_KEY_ENV_NAME, Library.AutoUpdater.AutoUpdateSettings.AppName + "_Key_42");
}
@@ -235,13 +220,13 @@ namespace Duplicati.Server foreach (string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType)))
if (s.Equals(commandlineOptions["log-level"].Trim(), StringComparison.InvariantCultureIgnoreCase))
Duplicati.Library.Logging.Log.LogLevel = (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s);
-
+
//Set the %DUPLICATI_HOME% env variable, if it is not already set
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(DATAFOLDER_ENV_NAME)))
{
#if DEBUG
//debug mode uses a lock file located in the app folder
- Environment.SetEnvironmentVariable(DATAFOLDER_ENV_NAME, System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
+ Environment.SetEnvironmentVariable(DATAFOLDER_ENV_NAME, StartupPath);
#else
bool portableMode = commandlineOptions.ContainsKey("portable-mode") ? Library.Utility.Utility.ParseBool(commandlineOptions["portable-mode"], true) : false;
@@ -263,7 +248,7 @@ namespace Duplicati.Server try
{
//This will also create Program.DATAFOLDER if it does not exist
- Instance = new SingleInstance(ApplicationName, Program.DATAFOLDER);
+ Instance = new SingleInstance(Duplicati.Library.AutoUpdater.AutoUpdateSettings.AppName, Program.DATAFOLDER);
}
catch (Exception ex)
{
@@ -358,13 +343,8 @@ namespace Duplicati.Server Program.DataConnection.ApplicationSettings.SetWebserverPassword(commandlineOptions["webservice-password"]);
ApplicationExitEvent = new System.Threading.ManualResetEvent(false);
-
- UpdateManager = new Duplicati.Library.AutoUpdater.UpdaterManager(
- Duplicati.License.AutoUpdateSettings.URLs,
- Duplicati.License.AutoUpdateSettings.SignKey,
- Duplicati.License.AutoUpdateSettings.AppName);
-
- UpdateManager.OnError += (Exception obj) => {
+
+ Duplicati.Library.AutoUpdater.UpdaterManager.OnError += (Exception obj) => {
Program.DataConnection.LogError(null, "Error in updater", obj);
};
diff --git a/Duplicati/Server/Serializable/ServerStatus.cs b/Duplicati/Server/Serializable/ServerStatus.cs index 084018951..c49b36e13 100644 --- a/Duplicati/Server/Serializable/ServerStatus.cs +++ b/Duplicati/Server/Serializable/ServerStatus.cs @@ -48,7 +48,7 @@ namespace Duplicati.Server.Serializable public UpdatePollerStates UpdaterState { get { return Program.UpdatePoller.ThreadState; } }
- public bool UpdateReady { get { return Program.UpdateManager.HasUpdateInstalled; } }
+ public bool UpdateReady { get { return Duplicati.Library.AutoUpdater.UpdaterManager.HasUpdateInstalled; } }
public Tuple<long, string> ActiveTask
diff --git a/Duplicati/Server/UpdatePollThread.cs b/Duplicati/Server/UpdatePollThread.cs index a14ef1c56..139ecfd1c 100644 --- a/Duplicati/Server/UpdatePollThread.cs +++ b/Duplicati/Server/UpdatePollThread.cs @@ -65,7 +65,7 @@ namespace Duplicati.Server public void ActivateUpdate()
{
- if (Program.UpdateManager.SetRunUpdate())
+ if (Duplicati.Library.AutoUpdater.UpdaterManager.SetRunUpdate())
Program.ApplicationExitEvent.Set();
}
@@ -105,7 +105,7 @@ namespace Duplicati.Server try
{
- var update = Program.UpdateManager.CheckForUpdate();
+ var update = Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate();
if (update != null && (Program.DataConnection.ApplicationSettings.UpdatedVersion == null || Program.DataConnection.ApplicationSettings.UpdatedVersion.ReleaseTime != update.ReleaseTime))
{
Program.DataConnection.ApplicationSettings.UpdatedVersion = update;
@@ -128,7 +128,7 @@ namespace Duplicati.Server ThreadState = UpdatePollerStates.Downloading;
Program.StatusEventNotifyer.SignalNewEvent();
- if (Program.UpdateManager.DownloadAndUnpackUpdate(v))
+ if (Duplicati.Library.AutoUpdater.UpdaterManager.DownloadAndUnpackUpdate(v))
Program.StatusEventNotifyer.SignalNewEvent();
}
}
diff --git a/Duplicati/Server/WebServer/ControlHandler.cs b/Duplicati/Server/WebServer/ControlHandler.cs index 601195971..17de0ef34 100644 --- a/Duplicati/Server/WebServer/ControlHandler.cs +++ b/Duplicati/Server/WebServer/ControlHandler.cs @@ -180,7 +180,7 @@ namespace Duplicati.Server.WebServer private void GetLicenseData(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
{
- bw.OutputOK(License.LicenseReader.ReadLicenses(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "licenses")));
+ bw.OutputOK(Duplicati.License.LicenseReader.ReadLicenses(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "licenses")));
}
private void RestoreFiles(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
@@ -270,7 +270,7 @@ namespace Duplicati.Server.WebServer APIVersion = 1,
PasswordPlaceholder = Duplicati.Server.WebServer.Server.PASSWORD_PLACEHOLDER,
ServerVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
- ServerVersionName = License.VersionNumbers.Version,
+ ServerVersionName = Duplicati.License.VersionNumbers.Version,
ServerTime = DateTime.Now,
OSType = Library.Utility.Utility.IsClientLinux ? (Library.Utility.Utility.IsClientOSX ? "OSX" : "Linux") : "Windows",
DirectorySeparator = System.IO.Path.DirectorySeparatorChar,
@@ -293,7 +293,7 @@ namespace Duplicati.Server.WebServer BackendModules = Serializable.ServerSettings.BackendModules,
GenericModules = Serializable.ServerSettings.GenericModules,
WebModules = Serializable.ServerSettings.WebModules,
- UsingAlternateUpdateURLs = License.AutoUpdateSettings.UsesAlternateURLs
+ UsingAlternateUpdateURLs = Duplicati.Library.AutoUpdater.AutoUpdateSettings.UsesAlternateURLs
});
}
@@ -519,7 +519,7 @@ namespace Duplicati.Server.WebServer try
{
// Add install defaults/overrides, if present
- var path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "newbackup.json");
+ var path = System.IO.Path.Combine(Duplicati.Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "newbackup.json");
if (System.IO.File.Exists(path))
{
Newtonsoft.Json.Linq.JObject n;
|