Changed the way the autoupdater probes for potential paths, such that it does not attempt to use ProgramFiles, even if it is write-able.

Added some better choices for storing update data on OSX.
This commit is contained in:
Kenneth Skovhede
2016-04-21 10:57:46 +02:00
parent 1ff0d2d92e
commit 7bbd9f3141
2 changed files with 112 additions and 21 deletions
+101 -21
View File
@@ -40,9 +40,10 @@ namespace Duplicati.Library.AutoUpdater
public 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( Duplicati.Library.Utility.Utility.getEntryAssembly().Location)
: System.Environment.GetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME));
private static readonly string INSTALLED_BASE_DIR =
string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable(string.Format(BASEINSTALLDIR_ENVNAME_TEMPLATE, APPNAME)))
? System.IO.Path.GetDirectoryName(Duplicati.Library.Utility.Utility.getEntryAssembly().Location)
: Library.Utility.Utility.ExpandEnvironmentVariables(System.Environment.GetEnvironmentVariable(string.Format(BASEINSTALLDIR_ENVNAME_TEMPLATE, APPNAME)));
private static readonly bool DISABLE_UPDATE_DOMAIN = !string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable(string.Format(SKIPUPDATE_ENVNAME_TEMPLATE, APPNAME)));
@@ -57,7 +58,8 @@ namespace Duplicati.Library.AutoUpdater
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 BASEINSTALLDIR_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_INSTALL_ROOT";
private const string UPDATEINSTALLDIR_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_UPDATE_ROOT";
internal const string SKIPUPDATE_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_SKIP_UPDATE";
private const string RUN_UPDATED_FOLDER_PATH = "AUTOUPDATER_LOAD_UPDATE";
private const string SLEEP_ENVNAME_TEMPLATE = "AUTOUPDATER_{0}_SLEEP";
@@ -80,26 +82,104 @@ namespace Duplicati.Library.AutoUpdater
static UpdaterManager()
{
string installdir = null;
var attempts = new string[] {
System.IO.Path.Combine(InstalledBaseDir, "updates"),
// Update folder strategy is a bit complicated,
// because it depends on the actual system,
// and because it tries to find a good spot
// by probing for locations
// Not defined on Non-Windows
string.IsNullOrWhiteSpace(System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles))
? null : System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), APPNAME, "updates"),
// The "overrides" paths are checked,
// to see if they exist and are writeable.
// The first existing and writeable path
// for "overrides" is chosen
System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), APPNAME, "updates"),
System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME, "updates"),
};
// If override was not found, the "legacypaths"
// are checked in the same way to see if
// we have previously used such a folder
// and if that folder has contents,
// which indicates that it has been used.
foreach(var p in attempts)
if (!string.IsNullOrWhiteSpace(p) && TestDirectoryIsWriteable(p))
{
installdir = p;
break;
}
// Finally we check the "attempts",
// which are suitable candidates
// for storing the updates on each
// operating system
if (string.IsNullOrWhiteSpace(System.Environment.GetEnvironmentVariable(string.Format(UPDATEINSTALLDIR_ENVNAME_TEMPLATE, APPNAME))))
{
string installdir = null;
var programfiles = System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
// The user can override updates by having a local updates folder
var overrides = new List<string>(new string [] {
System.IO.Path.Combine(InstalledBaseDir, "updates"),
});
if (Library.Utility.Utility.IsClientWindows)
{
overrides.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), APPNAME, "updates"));
overrides.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME, "updates"));
}
else
{
if (Library.Utility.Utility.IsClientOSX)
overrides.Add(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Application Support", APPNAME, "updates"));
overrides.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), APPNAME, "updates"));
}
// Previous locations that we don't want to use,
// but we keep them active to avoid breaking the update syste
var legacypaths = new List<string>();
if (!string.IsNullOrWhiteSpace(programfiles))
legacypaths.Add(System.IO.Path.Combine(programfiles, APPNAME, "updates"));
if (Library.Utility.Utility.IsClientLinux)
legacypaths.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), APPNAME, "updates"));
// The real attempts that we probe for
var attempts = new List<string>();
// We do not want to install anything in the basedir, if the application is installed in "ProgramFiles"
if (!string.IsNullOrWhiteSpace(programfiles) && !InstalledBaseDir.StartsWith(Library.Utility.Utility.AppendDirSeparator(programfiles)))
attempts.Add(System.IO.Path.Combine(InstalledBaseDir, "updates"));
if (Library.Utility.Utility.IsClientOSX)
attempts.Add(System.IO.Path.Combine("/", "Library", "Application Support", APPNAME, "updates"));
else
attempts.Add(System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), APPNAME, "updates"));
attempts.AddRange(overrides.Skip(1));
// Check if the override folder exists, and choose that
foreach (var p in overrides)
if (!string.IsNullOrWhiteSpace(p) && System.IO.Directory.Exists(p) && TestDirectoryIsWriteable(p))
{
installdir = p;
break;
}
if (string.IsNullOrWhiteSpace(installdir))
foreach (var p in legacypaths)
if (!string.IsNullOrWhiteSpace(p) && System.IO.Directory.Exists(p) && System.IO.Directory.EnumerateFiles(p, "*", System.IO.SearchOption.TopDirectoryOnly).Count() > 0 && TestDirectoryIsWriteable(p))
{
installdir = p;
break;
}
if (string.IsNullOrWhiteSpace(installdir))
foreach (var p in attempts)
if (!string.IsNullOrWhiteSpace(p) && TestDirectoryIsWriteable(p))
{
installdir = p;
break;
}
INSTALLDIR = installdir;
INSTALLDIR = installdir;
}
else
{
INSTALLDIR = Library.Utility.Utility.ExpandEnvironmentVariables(System.Environment.GetEnvironmentVariable(string.Format(UPDATEINSTALLDIR_ENVNAME_TEMPLATE, APPNAME)));
}
if (INSTALLDIR != null)
{
@@ -963,7 +1043,7 @@ namespace Duplicati.Library.AutoUpdater
}
}
Environment.SetEnvironmentVariable(string.Format(INSTALLDIR_ENVNAME_TEMPLATE, APPNAME), InstalledBaseDir);
Environment.SetEnvironmentVariable(string.Format(BASEINSTALLDIR_ENVNAME_TEMPLATE, APPNAME), InstalledBaseDir);
var folder = best.Key;
+11
View File
@@ -751,6 +751,17 @@ namespace Duplicati.Library.Utility
}
}
/// <summary>
/// Gets a value indicating if the client is Windows based
/// </summary>
public static bool IsClientWindows
{
get
{
return !IsClientLinux;
}
}
/// <value>
/// Returns a value indicating if the filesystem, is case sensitive
/// </value>