From 10b17dc367890bc3efeb32e3ec6afc832899e045 Mon Sep 17 00:00:00 2001
From: Daira Hopwood <daira@jacaranda.org>
Date: Tue, 21 Oct 2014 21:11:56 +0100
Subject: [PATCH] Make a start on the Windows installer.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
---
 .../windows/installer/.gitattributes          |   2 +
 .../windows/installer/installer.sln           |  20 +
 .../windows/installer/installer/app.rc        |   4 +
 .../windows/installer/installer/installer.cpp | 418 ++++++++++++++++++
 .../installer/installer/installer.vcproj      | 237 ++++++++++
 .../windows/installer/installer/logo.ico      | Bin 0 -> 304886 bytes
 .../windows/installer/installer/logo.svg      | 157 +++++++
 .../windows/installer/installer/make-icon.sh  |  23 +
 .../windows/installer/installer/stdafx.cpp    |   5 +
 .../windows/installer/installer/stdafx.h      |  29 ++
 .../windows/installer/installer/targetver.h   |  13 +
 .../setuptools/command/scriptsetup.py         |  15 +-
 12 files changed, 919 insertions(+), 4 deletions(-)
 create mode 100644 misc/build_helpers/windows/installer/.gitattributes
 create mode 100644 misc/build_helpers/windows/installer/installer.sln
 create mode 100644 misc/build_helpers/windows/installer/installer/app.rc
 create mode 100644 misc/build_helpers/windows/installer/installer/installer.cpp
 create mode 100644 misc/build_helpers/windows/installer/installer/installer.vcproj
 create mode 100644 misc/build_helpers/windows/installer/installer/logo.ico
 create mode 100644 misc/build_helpers/windows/installer/installer/logo.svg
 create mode 100755 misc/build_helpers/windows/installer/installer/make-icon.sh
 create mode 100644 misc/build_helpers/windows/installer/installer/stdafx.cpp
 create mode 100644 misc/build_helpers/windows/installer/installer/stdafx.h
 create mode 100644 misc/build_helpers/windows/installer/installer/targetver.h

diff --git a/misc/build_helpers/windows/installer/.gitattributes b/misc/build_helpers/windows/installer/.gitattributes
new file mode 100644
index 00000000..33ffd98d
--- /dev/null
+++ b/misc/build_helpers/windows/installer/.gitattributes
@@ -0,0 +1,2 @@
+installer.sln -text
+installer/installer.vcproj -text
diff --git a/misc/build_helpers/windows/installer/installer.sln b/misc/build_helpers/windows/installer/installer.sln
new file mode 100644
index 00000000..95d7a25d
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "installer", "installer\installer.vcproj", "{413A02C3-FBCC-42B4-9277-F1CCBDD274CA}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{413A02C3-FBCC-42B4-9277-F1CCBDD274CA}.Debug|Win32.ActiveCfg = Debug|Win32
+		{413A02C3-FBCC-42B4-9277-F1CCBDD274CA}.Debug|Win32.Build.0 = Debug|Win32
+		{413A02C3-FBCC-42B4-9277-F1CCBDD274CA}.Release|Win32.ActiveCfg = Release|Win32
+		{413A02C3-FBCC-42B4-9277-F1CCBDD274CA}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/misc/build_helpers/windows/installer/installer/app.rc b/misc/build_helpers/windows/installer/installer/app.rc
new file mode 100644
index 00000000..f82f4b65
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/app.rc
@@ -0,0 +1,4 @@
+#include <windows.h>
+#define IDC_STATIC -1
+
+100 ICON "logo.ico"
diff --git a/misc/build_helpers/windows/installer/installer/installer.cpp b/misc/build_helpers/windows/installer/installer/installer.cpp
new file mode 100644
index 00000000..f372e47d
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/installer.cpp
@@ -0,0 +1,418 @@
+// installer.cpp : Defines the entry point for the console application.
+//
+
+#include "stdafx.h"
+
+int wmain(int argc, wchar_t *argv[]);
+wchar_t * get_default_destination_dir();
+void self_extract(wchar_t *destination_dir);
+void empty_directory(wchar_t *destination_dir);
+void unzip_from_executable(wchar_t *executable_path, wchar_t *destination_dir);
+size_t read_uint32_le(unsigned char *b);
+void unzip(wchar_t *zip_path, wchar_t *destination_dir);
+void install_python(wchar_t *python_installer_dir);
+void scriptsetup(wchar_t *destination_dir);
+bool spawn_with_redirect(FILE *redirect, unsigned char *output_buf, size_t output_size, const wchar_t *argv[]);
+
+#define fail_unless(x, s) if (!(x)) { fail(s); }
+void fail(char *s);
+void warn(char *s);
+void pause();
+
+#define REQUIRED_PYTHON_VERSION_PREFIX "Python 2.7."
+#define PYTHON_INSTALLER_FILESPEC L"python*.msi"
+
+// defines PKGNAME_AND_VERSION, written by setup.py
+#include "_version.h"
+
+
+void noop_handler(const wchar_t * expression,
+                  const wchar_t * function,
+                  const wchar_t * file,
+                  unsigned int line,
+                  uintptr_t pReserved) {
+}
+
+int wmain(int argc, wchar_t *argv[]) {
+	_set_invalid_parameter_handler(noop_handler);
+
+	if (argc >= 2 && wcscmp(argv[1], L"--help") == 0) {
+		printf("installer <destination_dir>\n");
+		return 1;
+	}
+	wchar_t *destination_dir = (argc >= 2) ? argv[1] : get_default_destination_dir();
+
+	size_t len = wcslen(destination_dir);
+	// FIXME: strip trailing slash rather than rejecting it
+	fail_unless(len > 0 && destination_dir[len-1] != '\\' && len < MAX_PATH-1, "Invalid destination directory.");
+
+	self_extract(destination_dir);
+	install_python(destination_dir);
+	scriptsetup(destination_dir);
+	pause();
+
+	return 0;
+}
+
+wchar_t * get_default_destination_dir() {
+	// TODO: get Program Files directory from the registry
+	return L"C:\\Program Files\\Tahoe-LAFS";
+}
+
+void self_extract(wchar_t *destination_dir) {
+	wchar_t executable_path[MAX_PATH];
+
+	HMODULE hModule = GetModuleHandle(NULL);
+	fail_unless(hModule != NULL, "Could not get the module handle.");
+	GetModuleFileNameW(hModule, executable_path, MAX_PATH); 
+	fail_unless(GetLastError() == ERROR_SUCCESS, "Could not get the path of the current executable.");
+
+	empty_directory(destination_dir);
+	unzip_from_executable(executable_path, destination_dir);
+}
+
+void empty_directory(wchar_t *destination_dir) {
+	// Create an empty directory at destination_dir.
+	errno = 0;
+	int res = _wmkdir(destination_dir);
+	fail_unless((res == 0 && errno == 0) || errno == EEXIST, "Could not create destination directory.");
+}
+
+void unzip_from_executable(wchar_t *executable_path, wchar_t *destination_dir) {
+	// shell32's zipped folder implementation is strict about the zip format and
+	// does not support unzipping a self-extracting exe directly. So we copy the
+	// original zip file that was appended to the exe to a temporary directory,
+	// and use shell32 to unzip it from there. To get the length of the zip file,
+	// we look at its "end of central directory record", which is documented at
+	// <http://www.pkware.com/documents/casestudies/APPNOTE.TXT>.
+	// For simplicity we only handle the case of a zip file that has no archive
+	// comment, that does not use disk spanning, and that does not have a
+	// "Zip64 end of central directory record".
+
+	// APPNOTE.TXT section 4.3.16.
+	const size_t sizeof_eocd = 22;
+	unsigned char end_data[sizeof_eocd];
+	unsigned char eocd_signature[] = {0x50, 0x4B, 0x05, 0x06};
+	unsigned char comment_length[] = {0x00, 0x00};
+	unsigned char disk_num[] = {0x00, 0x00};
+
+	errno = 0;
+	FILE *f = _wfopen(executable_path, L"rb");
+	fail_unless(f != NULL && errno == 0 && ferror(f) == 0,
+		        "Could not open executable file.");
+
+	fseek(f, -(off_t) sizeof_eocd, SEEK_END);
+	fail_unless(errno == 0 && ferror(f) == 0,
+		        "Could not seek to end-of-central-directory record.");
+
+	__int64 eocd_offset = _ftelli64(f);
+	fail_unless(errno == 0 && ferror(f) == 0 && eocd_offset >= 0,
+		        "Could not read position of end-of-central-directory record.");
+	fail_unless(eocd_offset + sizeof_eocd <= 0xFFFFFFFFi64,
+		        "Cannot read an executable file >= 4 GiB.");
+
+	size_t n = fread(end_data, sizeof(end_data), 1, f);
+	fail_unless(n == 1 && errno == 0 && ferror(f) == 0,
+		        "Could not read end records.");
+
+	fail_unless(memcmp(end_data + sizeof(end_data) - sizeof(comment_length),
+		               comment_length, sizeof(comment_length)) == 0,
+		        "Cannot read a zip file that has an archive comment.");
+
+	fail_unless(memcmp(end_data, eocd_signature, sizeof(eocd_signature)) == 0,
+		        "Could not find the end-of-central-directory signature.");
+
+	fail_unless(memcmp(end_data + 4, disk_num, sizeof(disk_num)) == 0 &&
+		        memcmp(end_data + 6, disk_num, sizeof(disk_num)) == 0,
+		        "Cannot read a zipfile that spans disks.");
+
+	size_t cd_length = read_uint32_le(end_data + 12);
+	size_t cd_offset = read_uint32_le(end_data + 16);
+	__int64 zip_length = (__int64) cd_offset + cd_length + sizeof_eocd;
+	fail_unless(zip_length <= 0x7FFFFFFFi64,
+	            "Cannot copy a zip file >= 2 GiB.");
+
+	fseek(f, -(off_t) zip_length, SEEK_END);
+	fail_unless(errno == 0 && ferror(f) == 0,
+		        "Could not seek to start of embedded zip file.");
+
+	const wchar_t tmp_filename[] = L"tahoe-lafs.zip"; // FIXME make this more unique.
+	wchar_t tmp_path[MAX_PATH];
+	DWORD len = GetTempPathW(MAX_PATH, tmp_path);
+	fail_unless(len > 0, "Could not obtain temporary directory path.");
+	fail_unless(len < MAX_PATH - wcslen(tmp_filename), "Temporary directory path is too long.");
+	wcscpy(tmp_path + len, tmp_filename);
+
+	errno = 0;
+	FILE *tmp_file = _wfopen(tmp_path, L"wb");
+	fail_unless(tmp_file != NULL && errno == 0 && ferror(f) == 0,
+		        "Could not open temporary zip file.");
+
+	// FIXME: delete the temporary file if there is an error.
+	unsigned char buf[16384];
+	size_t remaining_length = (size_t) zip_length;
+	while (remaining_length > 0) {
+		size_t chunk_length = min(remaining_length, sizeof(buf));
+		n = fread(buf, chunk_length, 1, f);
+		fail_unless(n == 1 && errno == 0 && ferror(f) == 0,
+		            "Could not read from executable file.");
+		fwrite(buf, chunk_length, 1, tmp_file);
+		fail_unless(n == 1 && errno == 0 && ferror(f) == 0,
+		            "Could not write to temporary file.");
+		remaining_length -= chunk_length;
+	}
+	int res = fclose(tmp_file);
+	fail_unless(res == 0, "Could not close temporary zip file.");
+	fclose(f); // ignore errors
+
+	unzip(tmp_path, destination_dir);
+	_wunlink(tmp_path); // ignore errors
+}
+
+// read unsigned little-endian 32-bit integer
+size_t read_uint32_le(unsigned char *b) {
+	return ((size_t) b[0]      ) |
+		   ((size_t) b[1] <<  8) |
+		   ((size_t) b[2] << 16) |
+		   ((size_t) b[3] << 24);
+}
+
+void unzip(wchar_t *zip_path, wchar_t *destination_dir) {
+	// Based loosely on
+	// <https://social.msdn.microsoft.com/Forums/vstudio/en-US/45668d18-2840-4887-87e1-4085201f4103/visual-c-to-unzip-a-zip-file-to-a-specific-directory?forum=vclanguage>.
+
+	// CoInitializeEx: <http://msdn.microsoft.com/en-gb/library/windows/desktop/ms695279(v=vs.85).aspx>
+	HRESULT res = CoInitializeEx(NULL, 0);
+	fail_unless(res == S_OK || res == S_FALSE, "Could not initialize COM.");
+
+	// SysAllocString: <http://msdn.microsoft.com/en-gb/library/windows/desktop/ms221458(v=vs.85).aspx>
+	// BSTR: <http://msdn.microsoft.com/en-us/library/windows/desktop/ms221069(v=vs.85).aspx>
+
+	VARIANT zip_path_var;
+	zip_path_var.vt = VT_BSTR;
+	zip_path_var.bstrVal = SysAllocString(zip_path);
+	fail_unless(zip_path_var.bstrVal != NULL, "Could not allocate string for zip file path.");
+
+	VARIANT destination_dir_var;
+	destination_dir_var.vt = VT_BSTR;
+	destination_dir_var.bstrVal = SysAllocString(destination_dir);
+	fail_unless(destination_dir_var.bstrVal != NULL, "Could not allocate string for destination directory path.");
+
+	// CoCreateInstance: <http://msdn.microsoft.com/en-gb/library/windows/desktop/ms686615(v=vs.85).aspx>
+	IShellDispatch *shell;
+	res = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **) &shell);
+	fail_unless(res == S_OK, "Could not create Shell instance.");
+
+	// Folder.NameSpace: <http://msdn.microsoft.com/en-gb/library/windows/desktop/gg537721(v=vs.85).aspx>
+	Folder *zip_folder = NULL;
+	res = shell->NameSpace(zip_path_var, &zip_folder);
+	fail_unless(res == S_OK && zip_folder != NULL, "Could not create zip Folder object.");
+
+	Folder *destination_folder = NULL;
+	res = shell->NameSpace(destination_dir_var, &destination_folder);
+	fail_unless(res == S_OK && destination_folder != NULL, "Could not create destination Folder object.");
+
+	FolderItems *zip_folderitems = NULL;
+	zip_folder->Items(&zip_folderitems);
+	fail_unless(zip_folderitems != NULL, "Could not create zip FolderItems object.");
+
+	VARIANT zip_idispatch_var;
+	zip_idispatch_var.vt = VT_DISPATCH;
+	zip_idispatch_var.pdispVal = NULL;
+	zip_folderitems->QueryInterface(IID_IDispatch, (void **) &zip_idispatch_var.pdispVal);
+	fail_unless(zip_idispatch_var.pdispVal != NULL, "Could not create IDispatch for zip FolderItems object.");
+
+	// Folder.CopyHere: <http://msdn.microsoft.com/en-us/library/ms723207(v=vs.85).aspx>
+	//   (16) Respond with "Yes to All" for any dialog box that is displayed.
+	//  (256) Display a progress dialog box but do not show the file names.
+	//  (512) Do not confirm the creation of a new directory if the operation requires one to be created.
+	// (1024) Do not display a user interface if an error occurs.
+	// These options are ignored on Windows XP.
+	VARIANT options_var;
+	options_var.vt = VT_I4;
+	options_var.lVal = 16 | 256 | 512 | 1024;
+
+	res = destination_folder->CopyHere(zip_idispatch_var, options_var);
+	fail_unless(res == S_OK, "Could not extract zip file contents to destination directory.");
+
+	// We don't bother to free/release stuff unless we succeed, since we exit on failure.
+
+	// SysFreeString: <http://msdn.microsoft.com/en-gb/library/windows/desktop/ms221481(v=vs.85).aspx>
+	SysFreeString(zip_path_var.bstrVal);
+	SysFreeString(destination_dir_var.bstrVal);
+	zip_idispatch_var.pdispVal->Release();
+	zip_folderitems->Release();
+	destination_folder->Release();
+	zip_folder->Release();
+	shell->Release();
+
+	// CoUninitialize: <http://msdn.microsoft.com/en-gb/library/windows/desktop/ms688715(v=vs.85).aspx>
+	CoUninitialize();
+}
+
+void install_python(wchar_t *python_installer_dir) {
+	printf("Checking for " REQUIRED_PYTHON_VERSION_PREFIX "..\n");
+
+	unsigned char output_buf[1024];
+	const wchar_t *argv[] = { L"python", L"-V", NULL };
+	bool res = spawn_with_redirect(stderr, output_buf, sizeof(output_buf), &argv[0]);
+	if (res) {
+		printf("Found %s", (char *) output_buf);
+		if (strncmp((char *) output_buf, REQUIRED_PYTHON_VERSION_PREFIX, strlen(REQUIRED_PYTHON_VERSION_PREFIX)) == 0) {
+			return;
+		} else {
+			printf("but we need a newer version.\n");
+		}
+	} else {
+		printf("No Python found.\n");
+	}
+
+	wchar_t installer_pattern[MAX_PATH];
+	int n = _snwprintf(installer_pattern, MAX_PATH, L"%ls\\%ls", python_installer_dir, PYTHON_INSTALLER_FILESPEC);
+	fail_unless(n >= 0 && n < MAX_PATH, "Could not construct wildcard path to Python installer.");
+
+	WIN32_FIND_DATA find_data;
+	HANDLE search_handle = FindFirstFileW(installer_pattern, &find_data);
+	fail_unless(search_handle != INVALID_HANDLE_VALUE, "Could not find the Python installer.")
+
+	wchar_t installer_path[MAX_PATH];
+	n = _snwprintf(installer_path, MAX_PATH, L"%ls\\%ls", python_installer_dir, find_data.cFileName);
+	fail_unless(n >= 0 && n < MAX_PATH, "Could not construct path to Python installer.");
+	printf("%ls\n", installer_path);
+
+	wchar_t installer_path_quoted[2+MAX_PATH];
+	n = _snwprintf(installer_path_quoted, 2+MAX_PATH, L"\"%ls\"", installer_path);
+	fail_unless(n >= 0 && n < 2+MAX_PATH, "Could not construct quoted path to Python installer.");
+	printf("%ls\n", installer_path_quoted);
+
+	// <https://www.python.org/download/releases/2.5/msi/>
+	// XXX I'm not sure whether or not we want "/passive". These options
+	// may silently remove a previous Python installation that was not
+	// detected by the check above, and we'd like that to prompt.
+	const wchar_t *python_installer_argv[] = {
+		L"msiexec", L"/i", installer_path_quoted,
+		L"/passive", L"/norestart", L"ALLUSERS=1", L"ADDLOCAL=Extensions", NULL
+	};
+	errno = 0;
+	intptr_t exit_code = _wspawnvp(P_WAIT, python_installer_argv[0], python_installer_argv);
+	int saved_errno = errno;
+
+	_wunlink(installer_path); // ignore errors
+
+	fail_unless(saved_errno == 0, "Could not execute Python installer.");
+	fail_unless(exit_code == 0, "Python installer failed.");
+}
+
+void scriptsetup(wchar_t *destination_dir) {
+	// 12 = length of --addpath=""
+	wchar_t addpath_option_quoted[12+MAX_PATH];
+	int n = _snwprintf(addpath_option_quoted, 12+MAX_PATH, L"--addpath=\"%ls\\%ls\\bin\"", destination_dir, PKGNAME_AND_VERSION);
+	fail_unless(n >= 0 && n < 12+MAX_PATH, "Could not construct path for bin directory.");
+
+	unsigned char output_buf[10240];
+	const wchar_t *scriptsetup_argv[] = {
+		L"python", L"setup.py", L"scriptsetup",
+		L"--allusers", addpath_option_quoted,
+		NULL
+	};
+	bool res = spawn_with_redirect(stdout, output_buf, sizeof(output_buf), &scriptsetup_argv[0]);
+	puts((char *) output_buf);
+	fail_unless(res, "Could not set up Python to run the 'tahoe' command.");
+}
+
+bool spawn_with_redirect(FILE *redirect, unsigned char *output_buf, size_t output_size, const wchar_t *argv[]) {
+	bool result = false;
+	fail_unless(output_size > 0, "Invalid output_size.");
+	output_buf[0] = 0;
+
+	// Redirection is annoyingly complicated.
+	int output_pipe[2];
+	errno = 0;
+	int res = _pipe(output_pipe, 512, _O_BINARY | _O_NOINHERIT);
+	if (res != 0) {
+		warn("Could not create pipe.");
+		return false;
+	}
+	int output_read_fd = output_pipe[0], output_write_fd = output_pipe[1];
+
+	// Duplicate the redirected file descriptor (the call to _dup2 will close the original).
+	int original_fd = _dup(_fileno(redirect));
+	if (errno != 0) {
+		warn("Could not duplicate original file descriptor.");
+		return false;
+	}
+
+	// Duplicate write end of pipe to redirected file descriptor.
+	res = _dup2(output_write_fd, _fileno(redirect));
+	if (res != 0 || errno != 0) {
+		warn("Could not redirect.");
+		return false;
+	}
+
+	// Close original file descriptor for write end of pipe.
+	_close(output_write_fd); // ignore errors
+
+	HANDLE process_handle = (HANDLE) _wspawnvp(P_NOWAIT, argv[0], argv);
+	if (process_handle == (HANDLE) -1) {
+		warn("Could not execute subprocess.");
+	}
+
+	// Duplicate copy of original stdout back into stdout.
+	errno = 0;
+	res = _dup2(original_fd, _fileno(redirect));
+	fail_unless(res == 0 && errno == 0, "Could not restore stdout.");
+
+	// Close duplicate copy of original fd.
+	_close(original_fd); // ignore errors
+
+	if (process_handle == (HANDLE) -1) {
+		return false;
+	}
+
+	DWORD exit_code = 0;
+	errno = 0;
+	unsigned char *p = output_buf;
+	size_t remaining_size = output_size;
+	int bytes_read;
+	do {
+		if (remaining_size == 0) {
+			bytes_read = 0;
+			Sleep(100);
+		} else {
+			bytes_read = _read(output_read_fd, p, remaining_size-1);
+			if (errno != 0 || bytes_read < 0) {
+				warn("Could not read from subprocess output.");
+				return false;
+			}
+			fail_unless((size_t) bytes_read < output_size, "Unexpectedly long read.");
+			p += bytes_read;
+			remaining_size -= bytes_read;
+			*p = 0;
+		}
+
+		// GetExitCodeProcess: <http://msdn.microsoft.com/en-gb/library/windows/desktop/ms683189(v=vs.85).aspx>
+		BOOL res = GetExitCodeProcess(process_handle, &exit_code);
+		if (!res) {
+			warn("Could not get subprocess exit code.");
+			return false;
+		}
+	} while (bytes_read > 0 && exit_code == STILL_ACTIVE);
+
+	return (exit_code == 0);
+}
+
+void fail(char *s) {
+	// TODO: show dialog box
+	fprintf(stderr, "%s\n", s);
+	pause();
+	exit(1);
+}
+
+void warn(char *s) {
+	fprintf(stderr, "%s\n", s);
+}
+
+void pause() {
+	printf("Press any key to finish.\n");
+	_getch();
+}
\ No newline at end of file
diff --git a/misc/build_helpers/windows/installer/installer/installer.vcproj b/misc/build_helpers/windows/installer/installer/installer.vcproj
new file mode 100644
index 00000000..a2699a2b
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/installer.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="installer"
+	ProjectGUID="{413A02C3-FBCC-42B4-9277-F1CCBDD274CA}"
+	RootNamespace="installer"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				UACExecutionLevel="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+				VerboseOutput="true"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				Description="Making self-extracting executable..."
+				CommandLine="cmd /c &quot;copy /y /b $(OutDir)\$(ProjectName).exe+C:\tahoe\allmydata-tahoe-1.10.0.zip $(OutDir)\$(ProjectName).exe&quot;"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\installer.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\_version.h"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.h"
+				>
+			</File>
+			<File
+				RelativePath=".\targetver.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+			<File
+				RelativePath=".\app.rc"
+				>
+			</File>
+			<File
+				RelativePath=".\logo.ico"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/misc/build_helpers/windows/installer/installer/logo.ico b/misc/build_helpers/windows/installer/installer/logo.ico
new file mode 100644
index 0000000000000000000000000000000000000000..846567068128772052d16aaaa9b0a1429cb50432
GIT binary patch
literal 304886
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
T;m<P3#r^p$t=!7;S>XQzi@}>)

literal 0
HcmV?d00001

diff --git a/misc/build_helpers/windows/installer/installer/logo.svg b/misc/build_helpers/windows/installer/installer/logo.svg
new file mode 100644
index 00000000..6de798e3
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/logo.svg
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:h="http://www.w3.org/1999/xhtml"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="256"
+   height="256"
+   preserveAspectRatio="xMidYMid"
+   viewBox="-180 -180 256 256"
+   id="svg3480"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="logo.svg">
+  <metadata
+     id="metadata3511">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>Tahoe-LAFS logo</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="784"
+     inkscape:window-height="765"
+     id="namedview3509"
+     showgrid="false"
+     inkscape:zoom="0.921875"
+     inkscape:cx="128"
+     inkscape:cy="128"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg3480" />
+  <style
+     type="text/css"
+     id="style3482">
+  .storage {
+    fill: black;
+    stroke: none;
+  }
+  .arrow {
+    stroke: black;
+    stroke-width: 2;
+    marker-end: url(#arrowhead);
+  }
+</style>
+  <title
+     id="title3484">Tahoe-LAFS logo</title>
+  <desc
+     id="desc3486">
+    <h:p>A proposed logo for the Tahoe-LAFS Project.</h:p>
+    <h:p><h:a
+   rel="license"
+   href="http://creativecommons.org/licenses/by/3.0/">
+  <h:img
+     alt="Creative Commons License"
+     style="border-width:0"
+     src="http://i.creativecommons.org/l/by/3.0/88x31.png" />
+</h:a>
+<h:br />
+<h:span
+   href="http://purl.org/dc/dcmitype/StillImage"
+   property="dct:title"
+   rel="dct:type">Tahoe-LAFS Logo</h:span>
+ by <h:a
+   href="http://switchb.org/kpreid/2009/tahoe/"
+   property="cc:attributionName"
+   rel="cc:attributionURL">Kevin Reid</h:a>
+ is licensed under a <h:a
+   rel="license"
+   href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</h:a>
+.</h:p>
+  </desc>
+  <defs
+     id="defs3488">
+    <marker
+       id="arrowhead"
+       viewBox="0 -5 10 10"
+       refX="2"
+       refY="0"
+       markerUnits="userSpaceOnUse"
+       markerWidth="10"
+       markerHeight="10"
+       orient="auto">
+      <path
+         d="M 0 -3 L 9 0 L 0 3 z"
+         id="path3491" />
+    </marker>
+  </defs>
+  <g
+     transform="translate(-48 28) scale(3.4)"
+     id="g3493">
+    <line
+       class="arrow"
+       x1="0"
+       y1="0"
+       x2="0"
+       y2="-35"
+       id="line3495" />
+    <line
+       class="arrow"
+       x1="0"
+       y1="0"
+       x2="-8"
+       y2="-21"
+       id="line3497" />
+    <line
+       class="arrow"
+       x1="0"
+       y1="0"
+       x2="8"
+       y2="-21"
+       id="line3499" />
+    <circle
+       fill="red"
+       r="10"
+       id="circle3501"
+       d="M 10,0 C 10,5.5228475 5.5228475,10 0,10 -5.5228475,10 -10,5.5228475 -10,0 c 0,-5.5228475 4.4771525,-10 10,-10 5.5228475,0 10,4.4771525 10,10 z" />
+    <circle
+       class="storage"
+       r="8"
+       cy="-50"
+       id="circle3503"
+       d="m 8,-50 c 0,4.418278 -3.581722,8 -8,8 -4.418278,0 -8,-3.581722 -8,-8 0,-4.418278 3.581722,-8 8,-8 4.418278,0 8,3.581722 8,8 z" />
+    <circle
+       class="storage"
+       r="8"
+       cy="-35"
+       cx="-14"
+       id="circle3505"
+       d="m -6,-35 c 0,4.418278 -3.581722,8 -8,8 -4.418278,0 -8,-3.581722 -8,-8 0,-4.418278 3.581722,-8 8,-8 4.418278,0 8,3.581722 8,8 z" />
+    <circle
+       class="storage"
+       r="8"
+       cy="-35"
+       cx="14"
+       id="circle3507"
+       d="m 22,-35 c 0,4.418278 -3.581722,8 -8,8 -4.418278,0 -8,-3.581722 -8,-8 0,-4.418278 3.581722,-8 8,-8 4.418278,0 8,3.581722 8,8 z" />
+  </g>
+</svg>
diff --git a/misc/build_helpers/windows/installer/installer/make-icon.sh b/misc/build_helpers/windows/installer/installer/make-icon.sh
new file mode 100755
index 00000000..987e0ecb
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/make-icon.sh
@@ -0,0 +1,23 @@
+#! /bin/bash
+# Based on <http://stackoverflow.com/a/23688878/393146>
+# converts the passed-in svgs to ico
+
+if [[ $# -eq 0 ]]; then
+    echo "Usage: $0 svg1 [svg2 [...]]"
+    exit 0
+fi
+
+temp=$(mktemp -d)
+declare -a res=(16 24 32 48 64 256)
+for f in $*; do
+    mkdir -p $temp/$(dirname $f)
+    for r in "${res[@]}"; do
+        inkscape -z -e $temp/${f}${r}.png -w $r -h $r $f
+    done
+    resm=( "${res[@]/#/$temp/$f}" )
+    resm=( "${resm[@]/%/.png}" )
+    for filetype in ico; do
+        convert "${resm[@]}" ${f%%.*}.$filetype
+    done
+done
+rm -rf $temp
diff --git a/misc/build_helpers/windows/installer/installer/stdafx.cpp b/misc/build_helpers/windows/installer/installer/stdafx.cpp
new file mode 100644
index 00000000..c1026abd
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/stdafx.cpp
@@ -0,0 +1,5 @@
+// stdafx.cpp : source file that includes just the standard includes
+// installer.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/misc/build_helpers/windows/installer/installer/stdafx.h b/misc/build_helpers/windows/installer/installer/stdafx.h
new file mode 100644
index 00000000..9f8375b2
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/stdafx.h
@@ -0,0 +1,29 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include <stdio.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+#include <sys/stat.h>
+#include <conio.h>
+
+// Turn off the warnings nagging you to use the more complicated *_s
+// "secure" functions that are actually more difficult to use securely.
+#pragma warning(disable:4996)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <wtypes.h>
+#include <objbase.h>
+#include <shldisp.h>
+#include <shellapi.h>
diff --git a/misc/build_helpers/windows/installer/installer/targetver.h b/misc/build_helpers/windows/installer/installer/targetver.h
new file mode 100644
index 00000000..6fe8eb79
--- /dev/null
+++ b/misc/build_helpers/windows/installer/installer/targetver.h
@@ -0,0 +1,13 @@
+#pragma once
+
+// The following macros define the minimum required platform.  The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 
+// your application.  The macros work by enabling all features available on platform versions up to and 
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
+#endif
+
diff --git a/setuptools-0.6c16dev6.egg/setuptools/command/scriptsetup.py b/setuptools-0.6c16dev6.egg/setuptools/command/scriptsetup.py
index b3233ec1..b066820c 100644
--- a/setuptools-0.6c16dev6.egg/setuptools/command/scriptsetup.py
+++ b/setuptools-0.6c16dev6.egg/setuptools/command/scriptsetup.py
@@ -1,6 +1,6 @@
 from distutils.errors import DistutilsSetupError
 from setuptools import Command
-import sys
+import sys, os
 
 class scriptsetup(Command):
     action = (sys.platform == "win32"
@@ -10,11 +10,14 @@ class scriptsetup(Command):
     user_options = [
         ('allusers', 'a',
          'make changes for all users of this Windows installation (requires Administrator privileges)'),
+        ('addpath=', 'p',
+         'add a directory to the PATH (user by default; system if --allusers is specified)'),
     ]
     boolean_options = ['allusers']
 
     def initialize_options(self):
         self.allusers = False
+        self.addpath = None
 
     def finalize_options(self):
         pass
@@ -23,11 +26,13 @@ class scriptsetup(Command):
         if sys.platform != "win32":
             print "\n'scriptsetup' isn't needed on non-Windows platforms."
         else:
-            do_scriptsetup(self.allusers)
+            do_scriptsetup(self.allusers, self.addpath)
 
 
-def do_scriptsetup(allusers=False):
+def do_scriptsetup(allusers=False, addpath=None):
     print "\nSetting up environment to run scripts for %s..." % (allusers and "all users" or "the current user")
+    if addpath:
+		print "%r will be added to the PATH." % (addpath,)
 
     from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT, \
         REG_SZ, REG_EXPAND_SZ, KEY_QUERY_VALUE, KEY_SET_VALUE, \
@@ -247,13 +252,15 @@ def do_scriptsetup(allusers=False):
         except Exception, e:
             print "Warning: %r" % (e,)
 
-
     changed_assoc = associate(".pyscript", "Python.File", allusers)
 
     changed_env = False
     try:
         changed_env |= add_to_environment("PATHEXT", ".pyscript", allusers)
         changed_env |= add_to_environment("PATHEXT", ".pyw",      allusers)
+        if addpath:
+            abs_path = os.path.abspath(os.path.normpath(addpath))
+            changed_env |= add_to_environment("PATH", abs_path, allusers)
     finally:
         CloseKey(user_env)
         CloseKey(system_env)
-- 
2.45.2