diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Installer/win/StubBld | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Installer/win/StubBld/Makefile.kmk | 38 | ||||
-rw-r--r-- | src/VBox/Installer/win/StubBld/VBoxStubBld.cpp | 331 | ||||
-rw-r--r-- | src/VBox/Installer/win/StubBld/VBoxStubBld.h | 88 |
3 files changed, 457 insertions, 0 deletions
diff --git a/src/VBox/Installer/win/StubBld/Makefile.kmk b/src/VBox/Installer/win/StubBld/Makefile.kmk new file mode 100644 index 00000000..9abe040e --- /dev/null +++ b/src/VBox/Installer/win/StubBld/Makefile.kmk @@ -0,0 +1,38 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the stub builder. +# + +# +# Copyright (C) 2009-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# Not a build program as it is needed for repacking after we Get the MS driver blessing. +PROGRAMS += VBoxStubBld +VBoxStubBld_TEMPLATE = VBoxBldProg +VBoxStubBld_DEFS = _WIN32_WINNT=0x0400 VBOX_SVN_REV=$(VBOX_SVN_REV) $(VBOX_SVN_REV_KMK) +VBoxStubBld_SOURCES = VBoxStubBld.cpp + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp b/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp new file mode 100644 index 00000000..3e1320cc --- /dev/null +++ b/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp @@ -0,0 +1,331 @@ +/* $Id: VBoxStubBld.cpp $ */ +/** @file + * VBoxStubBld - VirtualBox's Windows installer stub builder. + */ + +/* + * Copyright (C) 2009-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/win/windows.h> +#include <shellapi.h> +#include <strsafe.h> + +#include <VBox/version.h> +#include <iprt/types.h> + +#include "VBoxStubBld.h" + + +static HRESULT GetFile(const char *pszFilePath, HANDLE *phFile, DWORD *pcbFile) +{ + HANDLE hFile = CreateFileA(pszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + SetLastError(NO_ERROR); + LARGE_INTEGER cbFile; + if (GetFileSizeEx(hFile, &cbFile)) + { + if (cbFile.HighPart == 0) + { + *pcbFile = cbFile.LowPart; + *phFile = hFile; + return S_OK; + } + fprintf(stderr, "error: File '%s' is too large: %llu bytes\n", pszFilePath, cbFile.QuadPart); + } + else + fprintf(stderr, "error: GetFileSizeEx failed on '%s': %lu\n", pszFilePath, GetLastError()); + CloseHandle(hFile); + } + else + fprintf(stderr, "error: CreateFileA failed on '%s': %lu\n", pszFilePath, GetLastError()); + *phFile = INVALID_HANDLE_VALUE; + return E_FAIL; +} + +static HRESULT MyUpdateResource(HANDLE hFile, DWORD cbFile, HANDLE hResourceUpdate, + const char *pszResourceType, const char *pszResourceId) +{ + HRESULT hr = E_FAIL; + HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hMap != NULL) + { + PVOID pvFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbFile); + if (pvFile) + { + if (UpdateResourceA(hResourceUpdate, pszResourceType, pszResourceId, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), pvFile, cbFile)) + hr = S_OK; + else + fprintf(stderr, "error: UpdateResourceA failed: %lu\n", GetLastError()); + + UnmapViewOfFile(pvFile); + } + else + fprintf(stderr, "error: MapViewOfFile failed: %lu\n", GetLastError()); + CloseHandle(hMap); + } + else + fprintf(stderr, "error: CreateFileMappingW failed: %lu\n", GetLastError()); + return hr; +} + +static HRESULT IntegrateFile(HANDLE hResourceUpdate, const char *pszResourceType, + const char *pszResourceId, const char *pszFilePath) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + DWORD cbFile = 0; + HRESULT hr = GetFile(pszFilePath, &hFile, &cbFile); + if (SUCCEEDED(hr)) + { + hr = MyUpdateResource(hFile, cbFile, hResourceUpdate, pszResourceType, pszResourceId); + if (FAILED(hr)) + printf("ERROR: Error updating resource for file %s!", pszFilePath); + CloseHandle(hFile); + } + else + hr = HRESULT_FROM_WIN32(GetLastError()); + return hr; +} + +static char *MyPathFilename(const char *pszPath) +{ + const char *pszName = pszPath; + for (const char *psz = pszPath;; psz++) + { + switch (*psz) + { + /* handle separators. */ + case ':': + pszName = psz + 1; + break; + + case '\\': + case '/': + pszName = psz + 1; + break; + + /* the end */ + case '\0': + if (*pszName) + return (char *)(void *)pszName; + return NULL; + } + } + + /* will never get here */ +} + + +int main(int argc, char* argv[]) +{ + /* + * Parse arguments. + */ + const char *pszSetupStub = "VBoxStub.exe"; + const char *pszOutput = "VirtualBox-MultiArch.exe"; + + printf(VBOX_PRODUCT " Stub Builder v%d.%d.%d.%d\n", + VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV); + + struct VBOXSTUBBUILDPKG + { + const char *pszSrcPath; + VBOXSTUBPKGARCH enmArch; + } aBuildPkgs[VBOXSTUB_MAX_PACKAGES] = { { NULL } }; + VBOXSTUBPKGHEADER StubHdr = + { + /*.szMagic = */ VBOXSTUBPKGHEADER_MAGIC_SZ, + /*.cPackages = */ 0 + }; + + for (int i = 1; i < argc; i++) + { + const char *pszArg = argv[i]; + if ( strcmp(pszArg, "--help") == 0 + || strcmp(pszArg, "-help") == 0 + || strcmp(pszArg, "-h") == 0 + || strcmp(pszArg, "-?") == 0) + { + printf("usage: %s -out <installer.exe> -stub <stub.exe> [-target-all <file>] [-target-<arch> <file>]\n", argv[0]); + return RTEXITCODE_SUCCESS; + } + + /* The remaining options all take a while. */ + if ( strcmp(pszArg, "-out") + && strcmp(pszArg, "-stub") + && strcmp(pszArg, "-target-all") + && strcmp(pszArg, "-target-x86") + && strcmp(pszArg, "-target-amd64")) + { + fprintf(stderr, "syntax error: Invalid parameter: %s\n", argv[i]); + return RTEXITCODE_SYNTAX; + } + + i++; + if (i >= argc) + { + fprintf(stderr, "syntax error: Option '%s' takes a value argument!\n", pszArg); + return RTEXITCODE_SYNTAX; + } + const char *pszValue = argv[i]; + + /* Process the individual options. */ + if (strcmp(pszArg, "-out") == 0) + pszOutput = pszValue; + else if (strcmp(pszArg, "-stub") == 0) + pszSetupStub = pszValue; + else + { + if (StubHdr.cPackages >= RT_ELEMENTS(aBuildPkgs)) + { + fprintf(stderr, "error: Too many packages specified!\n"); + return RTEXITCODE_FAILURE; + } + aBuildPkgs[StubHdr.cPackages].pszSrcPath = pszValue; + if (strcmp(pszArg, "-target-all") == 0) + aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_ALL; + else if (strcmp(pszArg, "-target-amd64") == 0) + aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_AMD64; + else if (strcmp(pszArg, "-target-x86") == 0) + aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_X86; + else + { + fprintf(stderr, "internal error: %u\n", __LINE__); + return RTEXITCODE_FAILURE; + } + StubHdr.cPackages++; + } + } + + if (StubHdr.cPackages == 0) + { + fprintf(stderr, "syntax error: No packages specified! Exiting.\n"); + return RTEXITCODE_SYNTAX; + } + + printf("Stub: %s\n", pszSetupStub); + printf("Output: %s\n", pszOutput); + printf("# Packages: %u\n", StubHdr.cPackages); + + /* + * Copy the stub over the output file. + */ + if (!CopyFile(pszSetupStub, pszOutput, FALSE)) + { + fprintf(stderr, "ERROR: Could not copy the stub loader: %lu\n", GetLastError()); + return RTEXITCODE_SYNTAX; + } + + /* + * Start updating the resources of the output file. + */ + HANDLE hUpdate = BeginUpdateResourceA(pszOutput, FALSE); + if (hUpdate) + { + /* + * Add the file one by one to the output file. + */ + HRESULT hrc = S_OK; + for (BYTE i = 0; i < StubHdr.cPackages; i++) + { + printf("Integrating (Platform %d): %s\n", aBuildPkgs[i].enmArch, aBuildPkgs[i].pszSrcPath); + + /* + * Create the package header. + */ + VBOXSTUBPKG Package = {0}; + Package.enmArch = aBuildPkgs[i].enmArch; + + /* The resource name */ + hrc = StringCchPrintf(Package.szResourceName, sizeof(Package.szResourceName), "BIN_%02d", i); + if (FAILED(hrc)) + { + fprintf(stderr, "Internal error: %u\n", __LINE__); + break; + } + + /* Construct final name used when extracting. */ + hrc = StringCchCopy(Package.szFilename, sizeof(Package.szFilename), MyPathFilename(aBuildPkgs[i].pszSrcPath)); + if (FAILED(hrc)) + { + fprintf(stderr, "ERROR: Filename is too long: %s\n", aBuildPkgs[i].pszSrcPath); + break; + } + + /* + * Add the package header to the binary. + */ + char szHeaderName[32]; + hrc = StringCchPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", i); + if (FAILED(hrc)) + { + fprintf(stderr, "Internal error: %u\n", __LINE__); + break; + } + + if (!UpdateResourceA(hUpdate, RT_RCDATA, szHeaderName, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + &Package, sizeof(Package))) + { + fprintf(stderr, "ERROR: UpdateResourceA failed for the package header: %lu\n", GetLastError()); + hrc = E_FAIL; + break; + } + + /* + * Add the file content under the BIN_xx resource name. + */ + hrc = IntegrateFile(hUpdate, RT_RCDATA, Package.szResourceName, aBuildPkgs[i].pszSrcPath); + if (FAILED(hrc)) + break; + } + if (SUCCEEDED(hrc)) + { + /* + * Now add the header/manifest and complete the operation. + */ + if (UpdateResourceA(hUpdate, RT_RCDATA, "MANIFEST", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + &StubHdr, sizeof(StubHdr))) + { + if (EndUpdateResourceA(hUpdate, FALSE /*fDiscard*/)) + { + printf("Successfully created the installer\n"); + return RTEXITCODE_SUCCESS; + } + fprintf(stderr, "ERROR: EndUpdateResourceA failed: %lu\n", GetLastError()); + } + else + fprintf(stderr, "ERROR: UpdateResourceA failed for the installer header/manifest: %lu\n", GetLastError()); + } + + EndUpdateResourceA(hUpdate, TRUE /*fDiscard*/); + hUpdate = NULL; + } + else + fprintf(stderr, "error: BeginUpdateResource failed: %lu\n", GetLastError()); + return RTEXITCODE_FAILURE; +} diff --git a/src/VBox/Installer/win/StubBld/VBoxStubBld.h b/src/VBox/Installer/win/StubBld/VBoxStubBld.h new file mode 100644 index 00000000..b0a4c382 --- /dev/null +++ b/src/VBox/Installer/win/StubBld/VBoxStubBld.h @@ -0,0 +1,88 @@ +/* $Id: VBoxStubBld.h $ */ +/** @file + * VBoxStubBld - VirtualBox's Windows installer stub builder. + */ + +/* + * Copyright (C) 2009-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifndef VBOX_INCLUDED_SRC_StubBld_VBoxStubBld_h +#define VBOX_INCLUDED_SRC_StubBld_VBoxStubBld_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> +#include <iprt/assertcompile.h> + +/**/ +#define VBOXSTUB_MAX_PACKAGES 128 + +/** */ +#define VBOXSTUBPKGHEADER_MAGIC_SZ "VBoxInstV1\0\0\0\0" + +/** + * VBox installer stub header, aka "MANIFEST". + * + * This just holds the number of packages present in the image. + */ +typedef struct VBOXSTUBPKGHEADER +{ + /** Magic value/string (VBOXSTUBPKGHEADER_MAGIC_SZ) */ + char szMagic[11 + 4]; + /** Number of packages following the header. */ + uint8_t cPackages; +} VBOXSTUBPKGHEADER; +AssertCompileSize(VBOXSTUBPKGHEADER, 16); +typedef VBOXSTUBPKGHEADER *PVBOXSTUBPKGHEADER; + +typedef enum VBOXSTUBPKGARCH +{ + /** Always extract. */ + VBOXSTUBPKGARCH_ALL = 1, + /** Extract on x86 hosts. */ + VBOXSTUBPKGARCH_X86, + /** Extract on AMD64 hosts. */ + VBOXSTUBPKGARCH_AMD64 +} VBOXSTUBPKGARCH; + +/** + * Package header/descriptor. + * + * This is found as "HDR_xx" where xx is replaced by the decimal package number, + * zero padded to two digits. + */ +typedef struct VBOXSTUBPKG +{ + /** The architecture for the file. */ + VBOXSTUBPKGARCH enmArch; + /** The name of the resource holding the file bytes. + * This is a pointless field, because the resource name is "BIN_xx" + * corresponding to the name of the resource containing this struct. */ + char szResourceName[28]; + /** The filename. */ + char szFilename[224]; +} VBOXSTUBPKG; +AssertCompileSize(VBOXSTUBPKG, 256); +typedef VBOXSTUBPKG *PVBOXSTUBPKG; + +#endif /* !VBOX_INCLUDED_SRC_StubBld_VBoxStubBld_h */ |