Skip to content

Commit

Permalink
Merge pull request #308 from Squirrel/program-data-insanity
Browse files Browse the repository at this point in the history
Install to ProgramData when LocalAppData is broken
  • Loading branch information
anaisbetts committed Apr 21, 2015
2 parents 9d1fc7c + d5e8032 commit 7be8bb0
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 93 deletions.
6 changes: 3 additions & 3 deletions src/Setup/Setup.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;secur32.lib</AdditionalDependencies>
</Link>
<Manifest>
<AdditionalManifestFiles>compat.manifest</AdditionalManifestFiles>
Expand All @@ -108,7 +108,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;secur32.lib</AdditionalDependencies>
</Link>
<Manifest>
<AdditionalManifestFiles>compat.manifest</AdditionalManifestFiles>
Expand All @@ -133,7 +133,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;urlmon.lib;secur32.lib</AdditionalDependencies>
</Link>
<Manifest>
<AdditionalManifestFiles>compat.manifest</AdditionalManifestFiles>
Expand Down
40 changes: 35 additions & 5 deletions src/Setup/UpdateRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ HRESULT CUpdateRunner::ShellExecuteFromExplorer(LPWSTR pszFile, LPWSTR pszParame
CComVariant(SW_SHOWDEFAULT));
}

int CUpdateRunner::ExtractUpdaterAndRun(wchar_t* lpCommandLine)
int CUpdateRunner::ExtractUpdaterAndRun(wchar_t* lpCommandLine, bool useFallbackDir)
{
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
Expand All @@ -137,15 +137,40 @@ int CUpdateRunner::ExtractUpdaterAndRun(wchar_t* lpCommandLine)
wchar_t logFile[MAX_PATH];
std::vector<CString> to_delete;

SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, targetDir);
if (!useFallbackDir) {
SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, targetDir);
} else {
wchar_t username[512];
wchar_t uid[128];
wchar_t appDataDir[MAX_PATH];
ULONG unameSize = _countof(username);

SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appDataDir);
GetUserName(username, &unameSize);
DWORD lastError = GetLastError();

_swprintf_c(targetDir, _countof(targetDir), L"%s\\%s", appDataDir, username);

if (!CreateDirectory(targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
wchar_t err[4096];
_swprintf_c(err, _countof(err), L"Unable to write to %s - IT policies may be restricting access to this folder", targetDir);
DisplayErrorMessage(CString(err), NULL);

return -1;
}
}

wcscat_s(targetDir, _countof(targetDir), L"\\SquirrelTemp");

if (!CreateDirectory(targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
wchar_t err[4096];
_swprintf_c(err, _countof(err), L"Unable to write to %s - IT policies may be restricting access to this folder", targetDir);
DisplayErrorMessage(CString(err), NULL);

return -1;
if (useFallbackDir) {
DisplayErrorMessage(CString(err), NULL);
}

goto failedExtract;
}

swprintf_s(logFile, L"%s\\SquirrelSetup.log", targetDir);
Expand Down Expand Up @@ -233,6 +258,11 @@ int CUpdateRunner::ExtractUpdaterAndRun(wchar_t* lpCommandLine)
return (int) dwExitCode;

failedExtract:
if (!useFallbackDir) {
// Take another pass at it, using C:\ProgramData instead
return ExtractUpdaterAndRun(lpCommandLine, true);
}

DisplayErrorMessage(CString(L"Failed to extract installer"), NULL);
return (int) dwExitCode;
}
}
2 changes: 1 addition & 1 deletion src/Setup/UpdateRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ class CUpdateRunner
public:
static HRESULT AreWeUACElevated();
static HRESULT ShellExecuteFromExplorer(LPWSTR pszFile, LPWSTR pszParameters);
static int ExtractUpdaterAndRun(wchar_t* lpCommandLine);
static int ExtractUpdaterAndRun(wchar_t* lpCommandLine, bool useFallbackDir);
};
2 changes: 2 additions & 0 deletions src/Setup/stdafx.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "targetver.h"

#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define SECURITY_WIN32

// Windows Header Files:
#include <windows.h>
Expand All @@ -28,6 +29,7 @@
#include <atlwin.h>

#include <windows.h>
#include <security.h>
#include <shlobj.h>
#include <exdisp.h>
#include <shlwapi.h>
Expand Down
4 changes: 2 additions & 2 deletions src/Setup/winmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
hr = _Module.Init(NULL, hInstance);

CString cmdLine(lpCmdLine);
bool isQuiet = (cmdLine.Find(L"/quiet") >= 0);
bool isQuiet = (cmdLine.Find(L"-s") >= 0);

if (!CFxHelper::IsDotNet45OrHigherInstalled()) {
hr = CFxHelper::InstallDotNetFramework(isQuiet);
Expand Down Expand Up @@ -51,7 +51,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
goto out;
}

exitCode = CUpdateRunner::ExtractUpdaterAndRun(lpCmdLine);
exitCode = CUpdateRunner::ExtractUpdaterAndRun(lpCmdLine, false);

out:
_Module.Term();
Expand Down
16 changes: 11 additions & 5 deletions src/Squirrel/DeltaPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public interface IDeltaPackageBuilder

public class DeltaPackageBuilder : IEnableLogger, IDeltaPackageBuilder
{
readonly string localAppDirectory;
public DeltaPackageBuilder(string localAppDataOverride = null)
{
this.localAppDirectory = localAppDataOverride;
}

public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile)
{
Contract.Requires(basePackage != null);
Expand Down Expand Up @@ -48,8 +54,8 @@ public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePack
string baseTempPath = null;
string tempPath = null;

using (Utility.WithTempDirectory(out baseTempPath))
using (Utility.WithTempDirectory(out tempPath)) {
using (Utility.WithTempDirectory(out baseTempPath, null))
using (Utility.WithTempDirectory(out tempPath, null)) {
var baseTempInfo = new DirectoryInfo(baseTempPath);
var tempInfo = new DirectoryInfo(tempPath);

Expand Down Expand Up @@ -89,8 +95,8 @@ public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePacka
string workingPath;
string deltaPath;

using (Utility.WithTempDirectory(out deltaPath))
using (Utility.WithTempDirectory(out workingPath)) {
using (Utility.WithTempDirectory(out deltaPath, localAppDirectory))
using (Utility.WithTempDirectory(out workingPath, localAppDirectory)) {
var fz = new FastZip();
fz.ExtractZip(deltaPackage.InputPackageFile, deltaPath, null);
fz.ExtractZip(basePackage.InputPackageFile, workingPath, null);
Expand Down Expand Up @@ -187,7 +193,7 @@ void applyDiffToFile(string deltaPath, string relativeFilePath, string workingDi
var finalTarget = Path.Combine(workingDirectory, Regex.Replace(relativeFilePath, @".diff$", ""));

var tempTargetFile = default(string);
Utility.WithTempFile(out tempTargetFile);
Utility.WithTempFile(out tempTargetFile, localAppDirectory);

try {
// NB: Zero-length diffs indicate the file hasn't actually changed
Expand Down
2 changes: 1 addition & 1 deletion src/Squirrel/ReleaseEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ public static List<ReleaseEntry> BuildReleasesFile(string releasePackagesDir)
// place
var entries = entriesQueue.ToList();
var tempFile = default(string);
Utility.WithTempFile(out tempFile);
Utility.WithTempFile(out tempFile, releasePackagesDir);

try {
using (var of = File.OpenWrite(tempFile)) {
Expand Down
2 changes: 1 addition & 1 deletion src/Squirrel/ReleasePackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public string CreateReleasePackage(string outputFile, string packagesRootDir = n

string tempPath = null;

using (Utility.WithTempDirectory(out tempPath)) {
using (Utility.WithTempDirectory(out tempPath, null)) {
var tempDir = new DirectoryInfo(tempPath);
var fz = new FastZip();

Expand Down
4 changes: 2 additions & 2 deletions src/Squirrel/UpdateManager.ApplyReleases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ async Task<ReleaseEntry> createFullPackagesFromDeltas(IEnumerable<ReleaseEntry>
var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", currentVersion.Filename));
var deltaPkg = new ReleasePackage(Path.Combine(rootAppDirectory, "packages", releasesToApply.First().Filename));

var deltaBuilder = new DeltaPackageBuilder();
var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName);

return deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg,
Regex.Replace(deltaPkg.InputPackageFile, @"-delta.nupkg$", ".nupkg", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant));
Expand Down Expand Up @@ -364,7 +364,7 @@ void executeSelfUpdate(Version currentVersion)
if (us != null && Path.GetFileName(us.Location).Equals("update.exe", StringComparison.OrdinalIgnoreCase)) {
var appName = targetDir.Parent.Name;

Process.Start(newSquirrel, "--updateSelf=" + appName);
Process.Start(newSquirrel, "--updateSelf=" + us.Location);
return;
}

Expand Down
46 changes: 32 additions & 14 deletions src/Squirrel/UpdateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,7 @@ public UpdateManager(string urlOrPath,
return;
}

// Determine the rootAppDirectory in such a way so that Portable
// Apps are more likely to work
var entry = Assembly.GetEntryAssembly();
if (entry != null) {
rootDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(entry.Location), "..", ".."));
}

this.rootAppDirectory = Path.Combine(rootDirectory ?? getLocalAppDataDirectory(), applicationName);

this.rootAppDirectory = Path.Combine(rootDirectory ?? GetLocalAppDataDirectory(), applicationName);
}

public async Task<UpdateInfo> CheckForUpdate(bool ignoreDeltaUpdates = false, Action<int> progress = null)
Expand Down Expand Up @@ -152,6 +144,10 @@ public string RootAppDirectory {
get { return rootAppDirectory; }
}

public bool IsInstalledApp {
get { return Assembly.GetExecutingAssembly().Location.StartsWith(RootAppDirectory, StringComparison.OrdinalIgnoreCase); }
}

public void Dispose()
{
var disp = Interlocked.Exchange(ref updateLock, null);
Expand Down Expand Up @@ -190,6 +186,33 @@ public static void RestartApp(string exeToStart = null, string arguments = null)
Environment.Exit(0);
}

public static string GetLocalAppDataDirectory(string assemblyLocation = null)
{
// Try to divine our our own install location via reading tea leaves
//
// * We're Update.exe, running in the app's install folder
// * We're Update.exe, running on initial install from SquirrelTemp
// * We're a C# EXE with Squirrel linked in

var assembly = Assembly.GetEntryAssembly();
if (assemblyLocation == null && assembly == null) {
// dunno lol
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
}

assemblyLocation = assemblyLocation ?? assembly.Location;

if (Path.GetFileName(assemblyLocation).Equals("update.exe", StringComparison.OrdinalIgnoreCase)) {
// NB: Both the "SquirrelTemp" case and the "App's folder" case
// mean that the root app dir is one up
var oneFolderUpFromAppFolder = Path.Combine(Path.GetDirectoryName(assemblyLocation), "..");
return Path.GetFullPath(oneFolderUpFromAppFolder);
}

var twoFoldersUpFromAppFolder = Path.Combine(Path.GetDirectoryName(assemblyLocation), "..\\..");
return Path.GetFullPath(twoFoldersUpFromAppFolder);
}

~UpdateManager()
{
if (updateLock != null && !exiting) {
Expand Down Expand Up @@ -242,10 +265,5 @@ static string getUpdateExe()
if (!target.Exists) throw new Exception("Update.exe not found, not a Squirrel-installed app?");
return target.FullName;
}

static string getLocalAppDataDirectory()
{
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
}
}
}
12 changes: 6 additions & 6 deletions src/Squirrel/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,20 +246,20 @@ internal static string tempNameForIndex(int index, string prefix)
return prefix + directoryChars.Value[index % directoryChars.Value.Length] + tempNameForIndex(index / directoryChars.Value.Length, "");
}

public static DirectoryInfo GetTempDirectory()
public static DirectoryInfo GetTempDirectory(string localAppDirectory)
{
var tempDir = Environment.GetEnvironmentVariable("SQUIRREL_TEMP");
tempDir = tempDir ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SquirrelTemp");
tempDir = tempDir ?? Path.Combine(localAppDirectory ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SquirrelTemp");

var di = new DirectoryInfo(tempDir);
if (!di.Exists) di.Create();

return di;
}

public static IDisposable WithTempDirectory(out string path)
public static IDisposable WithTempDirectory(out string path, string localAppDirectory = null)
{
var di = GetTempDirectory();
var di = GetTempDirectory(localAppDirectory);
var tempDir = default(DirectoryInfo);

var names = Enumerable.Range(0, 1<<20).Select(x => tempNameForIndex(x, "temp"));
Expand All @@ -279,9 +279,9 @@ public static IDisposable WithTempDirectory(out string path)
return Disposable.Create(() => Task.Run(async () => await DeleteDirectory(tempDir.FullName)).Wait());
}

public static IDisposable WithTempFile(out string path)
public static IDisposable WithTempFile(out string path, string localAppDirectory = null)
{
var di = GetTempDirectory();
var di = GetTempDirectory(localAppDirectory);
var names = Enumerable.Range(0, 1<<20).Select(x => tempNameForIndex(x, "temp"));

path = "";
Expand Down
Loading

0 comments on commit 7be8bb0

Please sign in to comment.