summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/mozilla_customizations.diff
diff options
context:
space:
mode:
Diffstat (limited to 'other-licenses/7zstub/mozilla_customizations.diff')
-rw-r--r--other-licenses/7zstub/mozilla_customizations.diff644
1 files changed, 644 insertions, 0 deletions
diff --git a/other-licenses/7zstub/mozilla_customizations.diff b/other-licenses/7zstub/mozilla_customizations.diff
new file mode 100644
index 0000000000..6680a6f893
--- /dev/null
+++ b/other-licenses/7zstub/mozilla_customizations.diff
@@ -0,0 +1,644 @@
+diff --git a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
+--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
++++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
+@@ -54,7 +54,7 @@ BSC32=bscmake.exe
+ # ADD BSC32 /nologo
+ LINK32=link.exe
+ # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+-# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zS.sfx" /opt:NOWIN98
++# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /nologo /subsystem:windows /machine:I386 /out:"Release\7zS.sfx" /opt:NOWIN98 /delayload:user32.dll /delayload:shell32.dll /delayload:oleaut32.dll
+ # SUBTRACT LINK32 /pdb:none
+
+ !ELSEIF "$(CFG)" == "SFXSetup - Win32 Debug"
+@@ -81,7 +81,7 @@ BSC32=bscmake.exe
+ # ADD BSC32 /nologo
+ LINK32=link.exe
+ # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zSfxS.exe" /pdbtype:sept
++# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug\7zSfxS.exe" /pdbtype:sept /delayload:user32.dll /delayload:shell32.dll /delayload:oleaut32.dll
+
+ !ELSEIF "$(CFG)" == "SFXSetup - Win32 ReleaseD"
+
+@@ -107,9 +107,9 @@ BSC32=bscmake.exe
+ # ADD BASE BSC32 /nologo
+ # ADD BSC32 /nologo
+ LINK32=link.exe
+-# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe"
++# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe"
+ # SUBTRACT BASE LINK32 /debug /nodefaultlib
+-# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zSD.sfx" /opt:NOWIN98
++# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /nologo /subsystem:windows /machine:I386 /out:"ReleaseD\7zSD.sfx" /opt:NOWIN98 /delayload:user32.dll /delayload:shell32.dll /delayload:oleaut32.dll
+ # SUBTRACT LINK32 /pdb:none
+
+ !ENDIF
+diff --git a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
+--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
++++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
+@@ -27,6 +27,10 @@
+
+ #include "resource.h"
+
++/* BEGIN Mozilla customizations */
++#include "../../../Common/IntToString.h"
++/* END Mozilla customizations */
++
+ using namespace NWindows;
+ using namespace NFile;
+ using namespace NDir;
+@@ -125,6 +129,398 @@ static void ShowErrorMessageSpec(const U
+ 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
+@@ -133,13 +529,35 @@ int APIENTRY WinMain(HINSTANCE hInstance
+ #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
+
+- #ifdef _WIN32
+- LoadSecurityDlls();
+- #endif
++ // 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();
+
+@@ -172,6 +590,18 @@ int APIENTRY WinMain(HINSTANCE hInstance
+ 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;
+@@ -204,7 +634,8 @@ int APIENTRY WinMain(HINSTANCE hInstance
+ }
+
+ CTempDir tempDir;
+- if (!tempDir.Create(kTempDirPrefix))
++ /* Mozilla customizations - Added !extractOnly */
++ if (!extractOnly && !tempDir.Create(kTempDirPrefix))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Can not create temp folder archive");
+@@ -222,7 +653,9 @@ int APIENTRY WinMain(HINSTANCE hInstance
+ }
+ }
+
+- const FString tempDirPath = tempDir.GetPath();
++ /* 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;
+@@ -250,6 +683,84 @@ int APIENTRY WinMain(HINSTANCE hInstance
+ }
+ }
+
++ /* 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))
+diff --git a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h
+--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h
++++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h
+@@ -4,3 +4,5 @@
+ #define IDS_EXTRACTION_ERROR_MESSAGE 8
+ #define IDS_CANNOT_CREATE_FOLDER 3003
+ #define IDS_PROGRESS_EXTRACTING 3300
++#define IDS_MIN_OS_TITLE 70
++#define IDS_MIN_OS_TEXT 71
+diff --git a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc
+--- a/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc
++++ b/other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc
+@@ -11,6 +11,8 @@ BEGIN
+ IDS_EXTRACTION_ERROR_MESSAGE "File is corrupt"
+ IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'"
+ IDS_PROGRESS_EXTRACTING "Extracting"
++ IDS_MIN_OS_TITLE "Setup Error"
++ IDS_MIN_OS_TEXT "Microsoft Windows 7 or newer is required."
+ END
+
+ #include "../../UI/FileManager/ProgressDialog.rc"
+diff --git a/other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp b/other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp
+--- a/other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp
++++ b/other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp
+@@ -165,7 +165,8 @@ bool CProgressDialog::OnButtonClicked(in
+ bool paused = Sync.GetPaused();
+ Sync.SetPaused(true);
+ _inCancelMessageBox = true;
+- int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNOCANCEL);
++ // Mozilla Customization - Removed redundant cancel button from dialog.
++ int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNO);
+ _inCancelMessageBox = false;
+ Sync.SetPaused(paused);
+ if (res == IDCANCEL || res == IDNO)