summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp')
-rw-r--r--other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp875
1 files changed, 875 insertions, 0 deletions
diff --git a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
new file mode 100644
index 0000000000..459c35d6e0
--- /dev/null
+++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
@@ -0,0 +1,875 @@
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/TextConfig.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/NtCheck.h"
+#include "../../../Windows/ResourceString.h"
+
+#include "../../UI/Explorer/MyMessages.h"
+
+#include "ExtractEngine.h"
+
+#include "../../../../C/DllSecur.h"
+
+#include "resource.h"
+
+/* BEGIN Mozilla customizations */
+#include "../../../Common/IntToString.h"
+/* END Mozilla customizations */
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+HINSTANCE g_hInstance;
+
+static CFSTR const kTempDirPrefix = FTEXT("7zS");
+
+#define _SHELL_EXECUTE
+
+static bool ReadDataString(CFSTR fileName, LPCSTR startID,
+ LPCSTR endID, AString &stringResult)
+{
+ stringResult.Empty();
+ NIO::CInFile inFile;
+ if (!inFile.Open(fileName))
+ return false;
+ const int kBufferSize = (1 << 12);
+
+ Byte buffer[kBufferSize];
+ int signatureStartSize = MyStringLen(startID);
+ int signatureEndSize = MyStringLen(endID);
+
+ UInt32 numBytesPrev = 0;
+ bool writeMode = false;
+ UInt64 posTotal = 0;
+ for (;;)
+ {
+ if (posTotal > (1 << 20))
+ return (stringResult.IsEmpty());
+ UInt32 numReadBytes = kBufferSize - numBytesPrev;
+ UInt32 processedSize;
+ if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize))
+ return false;
+ if (processedSize == 0)
+ return true;
+ UInt32 numBytesInBuffer = numBytesPrev + processedSize;
+ UInt32 pos = 0;
+ for (;;)
+ {
+ if (writeMode)
+ {
+ if (pos > numBytesInBuffer - signatureEndSize)
+ break;
+ if (memcmp(buffer + pos, endID, signatureEndSize) == 0)
+ return true;
+ char b = buffer[pos];
+ if (b == 0)
+ return false;
+ stringResult += b;
+ pos++;
+ }
+ else
+ {
+ if (pos > numBytesInBuffer - signatureStartSize)
+ break;
+ if (memcmp(buffer + pos, startID, signatureStartSize) == 0)
+ {
+ writeMode = true;
+ pos += signatureStartSize;
+ }
+ else
+ pos++;
+ }
+ }
+ numBytesPrev = numBytesInBuffer - pos;
+ posTotal += pos;
+ memmove(buffer, buffer + pos, numBytesPrev);
+ }
+}
+
+static char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 };
+static char kEndID[] = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 };
+
+struct CInstallIDInit
+{
+ CInstallIDInit()
+ {
+ kStartID[0] = ';';
+ kEndID[0] = ';';
+ };
+} g_CInstallIDInit;
+
+
+#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
+
+static void ShowErrorMessageSpec(const UString &name)
+{
+ UString message = NError::MyFormatMessage(::GetLastError());
+ int pos = message.Find(L"%1");
+ if (pos >= 0)
+ {
+ message.Delete(pos, 2);
+ message.Insert(pos, name);
+ }
+ ShowErrorMessage(NULL, message);
+}
+
+/* BEGIN Mozilla customizations */
+
+static char const *
+FindStrInBuf(char const * buf, size_t bufLen, char const * str)
+{
+ size_t index = 0;
+ while (index < bufLen) {
+ char const * result = strstr(buf + index, str);
+ if (result) {
+ return result;
+ }
+ while ((buf[index] != '\0') && (index < bufLen)) {
+ index++;
+ }
+ index++;
+ }
+ return NULL;
+}
+
+static bool
+ReadPostSigningDataFromView(char const * view, DWORD size, AString& data)
+{
+ // Find the offset and length of the certificate table,
+ // so we know the valid range to look for the token.
+ if (size < (0x3c + sizeof(UInt32))) {
+ return false;
+ }
+ UInt32 PEHeaderOffset = *(UInt32*)(view + 0x3c);
+ UInt32 optionalHeaderOffset = PEHeaderOffset + 24;
+ UInt32 certDirEntryOffset = 0;
+ if (size < (optionalHeaderOffset + sizeof(UInt16))) {
+ return false;
+ }
+ UInt16 magic = *(UInt16*)(view + optionalHeaderOffset);
+ if (magic == 0x010b) {
+ // 32-bit executable
+ certDirEntryOffset = optionalHeaderOffset + 128;
+ } else if (magic == 0x020b) {
+ // 64-bit executable; certain header fields are wider
+ certDirEntryOffset = optionalHeaderOffset + 144;
+ } else {
+ // Unknown executable
+ return false;
+ }
+ if (size < certDirEntryOffset + 8) {
+ return false;
+ }
+ UInt32 certTableOffset = *(UInt32*)(view + certDirEntryOffset);
+ UInt32 certTableLen = *(UInt32*)(view + certDirEntryOffset + sizeof(UInt32));
+ if (certTableOffset == 0 || certTableLen == 0 ||
+ size < (certTableOffset + certTableLen)) {
+ return false;
+ }
+
+ char const token[] = "__MOZCUSTOM__:";
+ // We're searching for a string inside a binary blob,
+ // so a normal strstr that bails on the first NUL won't work.
+ char const * tokenPos = FindStrInBuf(view + certTableOffset,
+ certTableLen, token);
+ if (tokenPos) {
+ size_t tokenLen = (sizeof(token) / sizeof(token[0])) - 1;
+ data = AString(tokenPos + tokenLen);
+ return true;
+ }
+ return false;
+}
+
+static bool
+ReadPostSigningData(UString exePath, AString& data)
+{
+ bool retval = false;
+ HANDLE exeFile = CreateFileW(exePath, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (exeFile != INVALID_HANDLE_VALUE) {
+ HANDLE mapping = CreateFileMapping(exeFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (mapping != INVALID_HANDLE_VALUE) {
+ // MSDN claims the return value on failure is NULL,
+ // but I've also seen it returned on success, so double-check.
+ if (mapping || GetLastError() == ERROR_SUCCESS) {
+ char * view = (char*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+ if (view) {
+ DWORD fileSize = GetFileSize(exeFile, NULL);
+ retval = ReadPostSigningDataFromView(view, fileSize, data);
+ }
+ CloseHandle(mapping);
+ }
+ }
+ CloseHandle(exeFile);
+ }
+ return retval;
+}
+
+// Simple class for allocating a character buffer and automatically freeing it
+// when it goes out of scope.
+class AutoCharBuffer {
+private:
+ char *buffer;
+
+ void Alloc(UInt32 size) {
+ buffer = new char[size];
+ length = 0;
+ }
+public:
+ // Other than being reset when the buffer is deallocated/reallocated, this
+ // isn't updated by this class.
+ UInt32 length;
+
+ AutoCharBuffer()
+ : length(0)
+ , buffer(NULL) {}
+
+ AutoCharBuffer(UInt32 size) {
+ Alloc(size);
+ }
+
+ void Realloc(UInt32 size) {
+ delete [] buffer;
+ Alloc(size);
+ }
+
+ void Dealloc() {
+ delete [] buffer;
+ buffer = NULL;
+ length = 0;
+ }
+
+ virtual ~AutoCharBuffer() {
+ Dealloc();
+ }
+
+ char *Buffer() {
+ return buffer;
+ }
+};
+
+static void
+AppendStringValueToIni(AString& iniData, const char* key, const char* value) {
+ iniData += key;
+ iniData += '=';
+ iniData += value;
+ iniData += '\n';
+}
+
+static void
+AppendDwordValueToIni(AString& iniData, const char* key, DWORD intValue) {
+ AString stringValue;
+ stringValue.Add_UInt32(intValue);
+ AppendStringValueToIni(iniData, key, stringValue.Ptr());
+}
+
+static void
+AppendQwordValueToIni(AString& iniData, const char* key, LONGLONG intValue) {
+ // The implementations for `Convert<int_type>ToString` are a little wonky and
+ // expect the output buffer to just be the correct size. To make sure we are
+ // using it right here, this int conversion implementation was copied from
+ // `CStdOutStream::operator<<(Int64 number)` in `StdOutStream.cpp`.
+ char stringValue[32];
+ ConvertInt64ToString(intValue, stringValue);
+ AppendStringValueToIni(iniData, key, stringValue);
+}
+
+static void
+ReadExeFileSystemIntoIniData(const UString &exePath, AString& iniData) {
+ const char* fsKey = "fileSystem";
+ const char* readFsErrorTypeKey = "readFsError";
+ const char* readFsErrorCodeKey = "readFsErrorCode";
+
+ HANDLE exeFile = CreateFileW(exePath, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (exeFile == INVALID_HANDLE_VALUE) {
+ DWORD errorCode = GetLastError();
+ AppendStringValueToIni(iniData, readFsErrorTypeKey, "openFile");
+ AppendDwordValueToIni(iniData, readFsErrorCodeKey, errorCode);
+ return;
+ }
+
+ const size_t bufferSize = MAX_PATH + 1;
+ wchar_t buffer[bufferSize];
+ BOOL success = GetVolumeInformationByHandleW(exeFile, NULL, 0, NULL, NULL,
+ NULL, buffer, bufferSize);
+ if (!success) {
+ DWORD errorCode = GetLastError();
+ AppendStringValueToIni(iniData, readFsErrorTypeKey, "getVolInfo");
+ AppendDwordValueToIni(iniData, readFsErrorCodeKey, errorCode);
+ CloseHandle(exeFile);
+ return;
+ }
+ CloseHandle(exeFile);
+
+ size_t fsLen = wcsnlen(buffer, bufferSize);
+ if (fsLen == bufferSize) {
+ AppendStringValueToIni(iniData, readFsErrorTypeKey, "fsUnterminated");
+ return;
+ }
+
+ const int narrowBufferSize = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL,
+ 0, NULL, NULL);
+ if (narrowBufferSize <= 0) {
+ DWORD errorCode = GetLastError();
+ AppendStringValueToIni(iniData, readFsErrorTypeKey, "getBufferSize");
+ AppendDwordValueToIni(iniData, readFsErrorCodeKey, errorCode);
+ return;
+ }
+ AutoCharBuffer fs(narrowBufferSize);
+ int written = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, fs.Buffer(),
+ narrowBufferSize, NULL, NULL);
+ if (written <= 0) {
+ DWORD errorCode = GetLastError();
+ AppendStringValueToIni(iniData, readFsErrorTypeKey, "convertString");
+ AppendDwordValueToIni(iniData, readFsErrorCodeKey, errorCode);
+ return;
+ }
+
+ // Like "fileSystem=FAT32" or "fileSystem=NTFS".
+ AppendStringValueToIni(iniData, fsKey, fs.Buffer());
+}
+
+// Read Zone Identifier information from alternate data stream.
+// Always either returns the data that was read, or data indicating what sort of
+// error was encountered when obtaining the data.
+// When this function returns, `metadata` is guaranteed to contain relevant
+// metadata that should be written out. But `data.Buffer()` may be null
+// depending on whether we successfully read data.
+static void
+ReadZoneIdentifierData(const UString &exePath, AString& metadata,
+ AutoCharBuffer& data)
+{
+ metadata.Empty();
+ data.Dealloc();
+
+ // We don't want to allow this function to just read an unlimited amount into
+ // `data`, so this value will control at what point we consider the file too
+ // big to be valid.
+ // 1 MB should be way more than enough. The Zone Identifier file generally
+ // consists of no more than 4 short lines of text.
+ const size_t maxReadSize = 1 * 1000 * 1000;
+ const char* readZoneIdErrorTypeKey = "readZoneIdError";
+ const char* readZoneIdErrorCodeKey = "readZoneIdErrorCode";
+ // It looks like the Zone Identifier will be INI data. But since there is no
+ // real guarantee of this, we are going to put an INI-compatible sentinel
+ // before we start appending the Zone Identifier file. This should help us
+ // better parse the file contents if we discover, say, that there is another
+ // possible format for Zone Identifier data.
+ const char* zoneIdStartSentinel = "\n[MozillaZoneIdentifierStartSentinel]\n";
+
+ metadata += "[Mozilla]\n";
+ ReadExeFileSystemIntoIniData(exePath, metadata);
+
+ UString adsPath(exePath);
+ // A colon (`:`) is not a valid path constituent (see
+ // https://learn.microsoft.com/en-ca/windows/win32/fileio/naming-a-file), so
+ // file systems that don't support ADS will fail to open rather than open an
+ // unrelated file.
+ adsPath += L":Zone.Identifier";
+ HANDLE adsFile = CreateFileW(adsPath, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (adsFile == INVALID_HANDLE_VALUE) {
+ DWORD errorCode = GetLastError();
+ AppendStringValueToIni(metadata, readZoneIdErrorTypeKey, "openFile");
+ AppendDwordValueToIni(metadata, readZoneIdErrorCodeKey, errorCode);
+ return;
+ }
+
+ LARGE_INTEGER fileSize;
+ BOOL success = GetFileSizeEx(adsFile, &fileSize);
+ UInt32 bufferSize = maxReadSize;
+ if (!success) {
+ AppendStringValueToIni(metadata, "zoneIdFileSize", "unknown");
+ AppendStringValueToIni(metadata, "zoneIdBufferLargeEnough", "unknown");
+ } else {
+ AppendQwordValueToIni(metadata, "zoneIdFileSize", fileSize.QuadPart);
+ if (fileSize.QuadPart < (LONGLONG)bufferSize) {
+ AppendStringValueToIni(metadata, "zoneIdBufferLargeEnough", "true");
+ bufferSize = (UInt32)fileSize.QuadPart;
+ } else {
+ AppendStringValueToIni(metadata, "zoneIdBufferLargeEnough", "false");
+ }
+ }
+ data.Realloc(bufferSize);
+
+ DWORD readCount;
+ success = ReadFile(adsFile, data.Buffer(), bufferSize, &readCount, NULL);
+ if (!success) {
+ DWORD errorCode = GetLastError();
+ AppendStringValueToIni(metadata, readZoneIdErrorTypeKey, "readFile");
+ AppendDwordValueToIni(metadata, readZoneIdErrorCodeKey, errorCode);
+
+ data.Dealloc();
+ CloseHandle(adsFile);
+ return;
+ }
+ data.length = readCount;
+
+ char dummyBuffer;
+
+ success = ReadFile(adsFile, &dummyBuffer, 1, &readCount, NULL);
+ CloseHandle(adsFile);
+ if (success) {
+ if (readCount == 0) {
+ // We are at the end of the file
+ AppendStringValueToIni(metadata, "zoneIdTruncated", "false");
+ } else {
+ AppendStringValueToIni(metadata, "zoneIdTruncated", "true");
+ }
+ } else {
+ AppendStringValueToIni(metadata, "zoneIdTruncated", "unknown");
+ }
+
+ metadata += zoneIdStartSentinel;
+}
+
+// Delayed load libraries are loaded when the first symbol is used.
+// The following ensures that we load the delayed loaded libraries from the
+// system directory.
+struct AutoLoadSystemDependencies
+{
+ AutoLoadSystemDependencies()
+ {
+ HMODULE module = ::GetModuleHandleW(L"kernel32.dll");
+ if (module) {
+ // SetDefaultDllDirectories is always available on Windows 8 and above. It
+ // is also available on Windows Vista, Windows Server 2008, and
+ // Windows 7 when MS KB2533623 has been applied.
+ typedef BOOL (WINAPI *SetDefaultDllDirectoriesType)(DWORD);
+ SetDefaultDllDirectoriesType setDefaultDllDirectories =
+ (SetDefaultDllDirectoriesType) GetProcAddress(module, "SetDefaultDllDirectories");
+ if (setDefaultDllDirectories) {
+ setDefaultDllDirectories(0x0800 /* LOAD_LIBRARY_SEARCH_SYSTEM32 */ );
+ return;
+ }
+ }
+
+ static LPCWSTR delayDLLs[] = { L"uxtheme.dll", L"userenv.dll",
+ L"setupapi.dll", L"apphelp.dll",
+ L"propsys.dll", L"dwmapi.dll",
+ L"cryptbase.dll", L"oleacc.dll",
+ L"clbcatq.dll" };
+ WCHAR systemDirectory[MAX_PATH + 1] = { L'\0' };
+ // If GetSystemDirectory fails we accept that we'll load the DLLs from the
+ // normal search path.
+ GetSystemDirectoryW(systemDirectory, MAX_PATH + 1);
+ size_t systemDirLen = wcslen(systemDirectory);
+
+ // Make the system directory path terminate with a slash
+ if (systemDirectory[systemDirLen - 1] != L'\\' && systemDirLen) {
+ systemDirectory[systemDirLen] = L'\\';
+ ++systemDirLen;
+ // No need to re-NULL terminate
+ }
+
+ // For each known DLL ensure it is loaded from the system32 directory
+ for (size_t i = 0; i < sizeof(delayDLLs) / sizeof(delayDLLs[0]); ++i) {
+ size_t fileLen = wcslen(delayDLLs[i]);
+ wcsncpy(systemDirectory + systemDirLen, delayDLLs[i],
+ MAX_PATH - systemDirLen);
+ if (systemDirLen + fileLen <= MAX_PATH) {
+ systemDirectory[systemDirLen + fileLen] = L'\0';
+ } else {
+ systemDirectory[MAX_PATH] = L'\0';
+ }
+ LPCWSTR fullModulePath = systemDirectory; // just for code readability
+ LoadLibraryW(fullModulePath);
+ }
+ }
+} loadDLLs;
+
+BOOL
+RemoveCurrentDirFromSearchPath()
+{
+ // kernel32.dll is in the knownDLL list so it is safe to load without a full path
+ HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
+ if (!kernel32) {
+ return FALSE;
+ }
+
+ typedef BOOL (WINAPI *SetDllDirectoryType)(LPCWSTR);
+ SetDllDirectoryType SetDllDirectoryFn =
+ (SetDllDirectoryType)GetProcAddress(kernel32, "SetDllDirectoryW");
+ if (!SetDllDirectoryFn) {
+ FreeLibrary(kernel32);
+ return FALSE;
+ }
+
+ // If this call fails we can't do much about it, so ignore it.
+ // It is unlikely to fail and this is just a precaution anyway.
+ SetDllDirectoryFn(L"");
+ FreeLibrary(kernel32);
+ return TRUE;
+}
+
+/* END Mozilla customizations */
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ /* lpCmdLine */,int /* nCmdShow */)
+{
+ /* BEGIN Mozilla customizations */
+ // Disable current directory from being in the search path.
+ // This call does not help with implicitly loaded DLLs.
+ if (!RemoveCurrentDirFromSearchPath()) {
+ WCHAR minOSTitle[512] = { '\0' };
+ WCHAR minOSText[512] = { '\0' };
+ LoadStringW(NULL, IDS_MIN_OS_TITLE, minOSTitle,
+ sizeof(minOSTitle) / sizeof(minOSTitle[0]));
+ LoadStringW(NULL, IDS_MIN_OS_TEXT, minOSText,
+ sizeof(minOSText) / sizeof(minOSText[0]));
+ MessageBoxW(NULL, minOSText, minOSTitle, MB_OK | MB_ICONERROR);
+ return 1;
+ }
+ /* END Mozilla customizations */
+
+ g_hInstance = (HINSTANCE)hInstance;
+
+ NT_CHECK
+
+ // BEGIN Mozilla customizations
+ // Our AutoLoadSystemDependencies (see above) does the same job as the
+ // LoadSecurityDlls function, but slightly better because it runs as a static
+ // initializer, and it doesn't include LOAD_LIBRARY_SEARCH_USER_DIRS in
+ // the search path, which partially defeats the purpose of calling
+ // SetDefaultDllDirectories at all.
+ //#ifdef _WIN32
+ //LoadSecurityDlls();
+ //#endif
+ // END Mozilla customizations
+
+ // InitCommonControls();
+
+ UString archiveName, switches;
+ #ifdef _SHELL_EXECUTE
+ UString executeFile, executeParameters;
+ #endif
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
+
+ FString fullPath;
+ NDLL::MyGetModuleFileName(fullPath);
+
+ switches.Trim();
+ bool assumeYes = false;
+ if (switches.IsPrefixedBy_Ascii_NoCase("-y"))
+ {
+ assumeYes = true;
+ switches = switches.Ptr(2);
+ switches.Trim();
+ }
+
+ AString config;
+ if (!ReadDataString(fullPath, kStartID, kEndID, config))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Can't load config info");
+ return 1;
+ }
+
+ UString dirPrefix ("." STRING_PATH_SEPARATOR);
+ UString appLaunched;
+ bool showProgress = true;
+
+ /* BEGIN Mozilla customizations */
+ bool extractOnly = false;
+ if (switches.IsPrefixedBy_NoCase(L"/extractdir=")) {
+ assumeYes = true;
+ showProgress = false;
+ extractOnly = true;
+ } else if (!switches.IsEmpty()) {
+ showProgress = false;
+ }
+ /* END Mozilla customizations */
+
+ if (!config.IsEmpty())
+ {
+ CObjectVector<CTextConfigPair> pairs;
+ if (!GetTextConfig(config, pairs))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Config failed");
+ return 1;
+ }
+ UString friendlyName = GetTextConfigValue(pairs, "Title");
+ UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt");
+ UString progress = GetTextConfigValue(pairs, "Progress");
+ if (progress.IsEqualTo_Ascii_NoCase("no"))
+ showProgress = false;
+ int index = FindTextConfigItem(pairs, "Directory");
+ if (index >= 0)
+ dirPrefix = pairs[index].String;
+ if (!installPrompt.IsEmpty() && !assumeYes)
+ {
+ if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |
+ MB_ICONQUESTION) != IDYES)
+ return 0;
+ }
+ appLaunched = GetTextConfigValue(pairs, "RunProgram");
+
+ #ifdef _SHELL_EXECUTE
+ executeFile = GetTextConfigValue(pairs, "ExecuteFile");
+ executeParameters = GetTextConfigValue(pairs, "ExecuteParameters");
+ #endif
+ }
+
+ CTempDir tempDir;
+ /* Mozilla customizations - Added !extractOnly */
+ if (!extractOnly && !tempDir.Create(kTempDirPrefix))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Can not create temp folder archive");
+ return 1;
+ }
+
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr<IUnknown> compressCodecsInfo = codecs;
+ {
+ HRESULT result = codecs->Load();
+ if (result != S_OK)
+ {
+ ShowErrorMessage(L"Can not load codecs");
+ return 1;
+ }
+ }
+
+ /* BEGIN Mozilla customizations - added extractOnly parameter support */
+ const FString tempDirPath = extractOnly ? switches.Ptr(12) : GetUnicodeString(tempDir.GetPath());
+ /* END Mozilla customizations */
+ // tempDirPath = L"M:\\1\\"; // to test low disk space
+ {
+ bool isCorrupt = false;
+ UString errorMessage;
+ HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
+ isCorrupt, errorMessage);
+
+ if (result != S_OK)
+ {
+ if (!assumeYes)
+ {
+ if (result == S_FALSE || isCorrupt)
+ {
+ NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage);
+ result = E_FAIL;
+ }
+ if (result != E_ABORT)
+ {
+ if (errorMessage.IsEmpty())
+ errorMessage = NError::MyFormatMessage(result);
+ ::MessageBoxW(0, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
+ }
+ }
+ return 1;
+ }
+ }
+
+ /* BEGIN Mozilla customizations */
+ // Retrieve and store any data added to this file after signing.
+ {
+ AString postSigningData;
+ if (ReadPostSigningData(fullPath, postSigningData)) {
+ FString postSigningDataFilePath(tempDirPath);
+ NFile::NName::NormalizeDirPathPrefix(postSigningDataFilePath);
+ postSigningDataFilePath += L"postSigningData";
+
+ NFile::NIO::COutFile postSigningDataFile;
+ postSigningDataFile.Create(postSigningDataFilePath, true);
+
+ UInt32 written = 0;
+ postSigningDataFile.Write(postSigningData, postSigningData.Len(), written);
+ }
+ }
+
+ // Read Zone Identifier information
+ // This will consist of two types of data that we will write to the same file.
+ // First we have the metadata, which will be INI data with these possible
+ // keys:
+ // - `fileSystem`: What file system the executable is on
+ // - `readFsError`: A string describing why we couldn't get the file system.
+ // Either this key will be present or the `fileSystem` key
+ // will be.
+ // - `readFsErrorCode`: An integer returned by `GetLastError()` indicating,
+ // in more detail, why we failed to obtain the file
+ // system. This key may exist if `readFsError` exists.
+ // - `readZoneIdError`: A string describing why we couldn't get the
+ // provenance data.
+ // - `readZoneIdErrorCode`: An integer returned by `GetLastError()`
+ // indicating, in more detail, why we failed to get the
+ // provenance data. This key may exist if
+ // `readZoneIdError` exists.
+ // - `zoneIdFileSize`: Either `"unknown"`, or an integer indicating the
+ // number of bytes in the zone identifier ADS.
+ // - `zoneIdBufferLargeEnough`: Either `"unknown"`, `"true"`, or `"false"`,
+ // indicating whether the file size was bigger
+ // than the maximum size that we will read from
+ // that file.
+ // - `zoneIdTruncated`: Either `"unknown"`, `"true"`, or `"false"`. Indicates
+ // whether or not we saw the end of the ADS file when we
+ // read from it.
+ // The above keys will be in the `"[Mozilla]"` section of the metadata.
+ // The other type of data that will go into the file is the directly copied
+ // data from the Zone Identifier ADS. This _should_ also be INI data, making
+ // the entirety of the file valid INI data.
+ // In the "good" case, this makes things very easy for us since INI reading
+ // functionality is already available. If we see an unexpected amount of
+ // telemetry data reporting that the INI is invalid, we will probably need to
+ // determine what other data formats are possible in that ADS.
+ // To make it easier to separate out the Zone Identifier data from the
+ // metadata, in that case, the metadata will always end with this sentinel,
+ // as long as `zoneIdData` contains valid data:
+ // `"\n[MozillaZoneIdentifierStartSentinel]\n"`
+ {
+ AString metadata;
+ AutoCharBuffer zoneIdData;
+ ReadZoneIdentifierData(fullPath, metadata, zoneIdData);
+ FString zoneIdDataFilePath(tempDirPath);
+ NFile::NName::NormalizeDirPathPrefix(zoneIdDataFilePath);
+ zoneIdDataFilePath += L"zoneIdProvenanceData";
+
+ NFile::NIO::COutFile zoneIdDataFile;
+ zoneIdDataFile.Create(zoneIdDataFilePath, true);
+
+ UInt32 written = 0;
+ zoneIdDataFile.Write(metadata, metadata.Len(), written);
+ if (zoneIdData.length > 0 && zoneIdData.Buffer()) {
+ zoneIdDataFile.Write(zoneIdData.Buffer(), zoneIdData.length, written);
+ }
+ }
+
+ if (extractOnly) {
+ return 0;
+ }
+ /* END Mozilla customizations */
+
+ #ifndef UNDER_CE
+ CCurrentDirRestorer currentDirRestorer;
+ if (!SetCurrentDir(tempDirPath))
+ return 1;
+ #endif
+
+ HANDLE hProcess = 0;
+#ifdef _SHELL_EXECUTE
+ if (!executeFile.IsEmpty())
+ {
+ CSysString filePath (GetSystemString(executeFile));
+ SHELLEXECUTEINFO execInfo;
+ execInfo.cbSize = sizeof(execInfo);
+ execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
+ #ifndef UNDER_CE
+ | SEE_MASK_FLAG_DDEWAIT
+ #endif
+ ;
+ execInfo.hwnd = NULL;
+ execInfo.lpVerb = NULL;
+ execInfo.lpFile = filePath;
+
+ if (!switches.IsEmpty())
+ {
+ executeParameters.Add_Space_if_NotEmpty();
+ executeParameters += switches;
+ }
+
+ CSysString parametersSys (GetSystemString(executeParameters));
+ if (parametersSys.IsEmpty())
+ execInfo.lpParameters = NULL;
+ else
+ execInfo.lpParameters = parametersSys;
+
+ execInfo.lpDirectory = NULL;
+ execInfo.nShow = SW_SHOWNORMAL;
+ execInfo.hProcess = 0;
+ /* BOOL success = */ ::ShellExecuteEx(&execInfo);
+ UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
+ if (result <= 32)
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Can not open file");
+ return 1;
+ }
+ hProcess = execInfo.hProcess;
+ }
+ else
+#endif
+ {
+ if (appLaunched.IsEmpty())
+ {
+ appLaunched = L"setup.exe";
+ if (!NFind::DoesFileExist(us2fs(appLaunched)))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Can not find setup.exe");
+ return 1;
+ }
+ }
+
+ {
+ FString s2 = tempDirPath;
+ NName::NormalizeDirPathPrefix(s2);
+ appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));
+ }
+
+ UString appNameForError = appLaunched; // actually we need to rtemove parameters also
+
+ appLaunched.Replace(L"%%T", fs2us(tempDirPath));
+
+ if (!switches.IsEmpty())
+ {
+ appLaunched.Add_Space();
+ appLaunched += switches;
+ }
+ STARTUPINFO startupInfo;
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpReserved = 0;
+ startupInfo.lpDesktop = 0;
+ startupInfo.lpTitle = 0;
+ startupInfo.dwFlags = 0;
+ startupInfo.cbReserved2 = 0;
+ startupInfo.lpReserved2 = 0;
+
+ PROCESS_INFORMATION processInformation;
+
+ CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched));
+
+ BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,
+ NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
+ &startupInfo, &processInformation);
+ if (createResult == 0)
+ {
+ if (!assumeYes)
+ {
+ // we print name of exe file, if error message is
+ // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application".
+ ShowErrorMessageSpec(appNameForError);
+ }
+ return 1;
+ }
+ ::CloseHandle(processInformation.hThread);
+ hProcess = processInformation.hProcess;
+ }
+ if (hProcess != 0)
+ {
+ WaitForSingleObject(hProcess, INFINITE);
+ ::CloseHandle(hProcess);
+ }
+ return 0;
+}