VirtualBox

source: vbox/trunk/src/VBox/Installer/win/StubBld/VBoxStubBld.cpp@ 106984

Last change on this file since 106984 was 106984, checked in by vboxsync, 2 months ago

Installer/win/Stub*: ARM64 changes. Kicked out unnecessary VBoxStub.h header file. jiraref:VBP-1442

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: VBoxStubBld.cpp 106984 2024-11-13 12:54:01Z vboxsync $ */
2/** @file
3 * VBoxStubBld - VirtualBox's Windows installer stub builder.
4 */
5
6/*
7 * Copyright (C) 2009-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/win/windows.h>
33#include <shellapi.h>
34#include <strsafe.h>
35
36#include <VBox/version.h>
37#include <iprt/types.h>
38
39#include "VBoxStubBld.h"
40
41
42static HRESULT GetFile(const char *pszFilePath, HANDLE *phFile, DWORD *pcbFile)
43{
44 HANDLE hFile = CreateFileA(pszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
45 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
46 if (hFile != INVALID_HANDLE_VALUE)
47 {
48 SetLastError(NO_ERROR);
49 LARGE_INTEGER cbFile;
50 if (GetFileSizeEx(hFile, &cbFile))
51 {
52 if (cbFile.HighPart == 0)
53 {
54 *pcbFile = cbFile.LowPart;
55 *phFile = hFile;
56 return S_OK;
57 }
58 fprintf(stderr, "error: File '%s' is too large: %llu bytes\n", pszFilePath, cbFile.QuadPart);
59 }
60 else
61 fprintf(stderr, "error: GetFileSizeEx failed on '%s': %lu\n", pszFilePath, GetLastError());
62 CloseHandle(hFile);
63 }
64 else
65 fprintf(stderr, "error: CreateFileA failed on '%s': %lu\n", pszFilePath, GetLastError());
66 *phFile = INVALID_HANDLE_VALUE;
67 return E_FAIL;
68}
69
70static HRESULT MyUpdateResource(HANDLE hFile, DWORD cbFile, HANDLE hResourceUpdate,
71 const char *pszResourceType, const char *pszResourceId)
72{
73 HRESULT hr = E_FAIL;
74 HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
75 if (hMap != NULL)
76 {
77 PVOID pvFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbFile);
78 if (pvFile)
79 {
80 if (UpdateResourceA(hResourceUpdate, pszResourceType, pszResourceId,
81 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), pvFile, cbFile))
82 hr = S_OK;
83 else
84 fprintf(stderr, "error: UpdateResourceA failed: %lu\n", GetLastError());
85
86 UnmapViewOfFile(pvFile);
87 }
88 else
89 fprintf(stderr, "error: MapViewOfFile failed: %lu\n", GetLastError());
90 CloseHandle(hMap);
91 }
92 else
93 fprintf(stderr, "error: CreateFileMappingW failed: %lu\n", GetLastError());
94 return hr;
95}
96
97static HRESULT IntegrateFile(HANDLE hResourceUpdate, const char *pszResourceType,
98 const char *pszResourceId, const char *pszFilePath)
99{
100 HANDLE hFile = INVALID_HANDLE_VALUE;
101 DWORD cbFile = 0;
102 HRESULT hr = GetFile(pszFilePath, &hFile, &cbFile);
103 if (SUCCEEDED(hr))
104 {
105 hr = MyUpdateResource(hFile, cbFile, hResourceUpdate, pszResourceType, pszResourceId);
106 if (FAILED(hr))
107 printf("ERROR: Error updating resource for file %s!", pszFilePath);
108 CloseHandle(hFile);
109 }
110 else
111 hr = HRESULT_FROM_WIN32(GetLastError());
112 return hr;
113}
114
115static char *MyPathFilename(const char *pszPath)
116{
117 const char *pszName = pszPath;
118 for (const char *psz = pszPath;; psz++)
119 {
120 switch (*psz)
121 {
122 /* handle separators. */
123 case ':':
124 pszName = psz + 1;
125 break;
126
127 case '\\':
128 case '/':
129 pszName = psz + 1;
130 break;
131
132 /* the end */
133 case '\0':
134 if (*pszName)
135 return (char *)(void *)pszName;
136 return NULL;
137 }
138 }
139
140 /* will never get here */
141}
142
143
144int main(int argc, char* argv[])
145{
146 /*
147 * Parse arguments.
148 */
149 const char *pszSetupStub = "VBoxStub.exe";
150 const char *pszOutput = "VirtualBox-MultiArch.exe";
151
152 printf(VBOX_PRODUCT " Stub Builder v%d.%d.%d.%d\n",
153 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
154
155 struct VBOXSTUBBUILDPKG
156 {
157 const char *pszSrcPath;
158 VBOXSTUBPKGARCH enmArch;
159 } aBuildPkgs[VBOXSTUB_MAX_PACKAGES] = { { NULL } };
160 VBOXSTUBPKGHEADER StubHdr =
161 {
162 /*.szMagic = */ VBOXSTUBPKGHEADER_MAGIC_SZ,
163 /*.cPackages = */ 0
164 };
165
166 for (int i = 1; i < argc; i++)
167 {
168 const char *pszArg = argv[i];
169 if ( strcmp(pszArg, "--help") == 0
170 || strcmp(pszArg, "-help") == 0
171 || strcmp(pszArg, "-h") == 0
172 || strcmp(pszArg, "-?") == 0)
173 {
174 printf("usage: %s -out <installer.exe> -stub <stub.exe> [-target-all <file>] [-target-<arch> <file>]\n", argv[0]);
175 return RTEXITCODE_SUCCESS;
176 }
177
178 /* The remaining options all take a while. */
179 if ( strcmp(pszArg, "-out")
180 && strcmp(pszArg, "-stub")
181 && strcmp(pszArg, "-target-all")
182 && strcmp(pszArg, "-target-x86")
183 && strcmp(pszArg, "-target-amd64")
184 && strcmp(pszArg, "-target-arm64"))
185 {
186 fprintf(stderr, "syntax error: Invalid parameter: %s\n", argv[i]);
187 return RTEXITCODE_SYNTAX;
188 }
189
190 i++;
191 if (i >= argc)
192 {
193 fprintf(stderr, "syntax error: Option '%s' takes a value argument!\n", pszArg);
194 return RTEXITCODE_SYNTAX;
195 }
196 const char *pszValue = argv[i];
197
198 /* Process the individual options. */
199 if (strcmp(pszArg, "-out") == 0)
200 pszOutput = pszValue;
201 else if (strcmp(pszArg, "-stub") == 0)
202 pszSetupStub = pszValue;
203 else
204 {
205 if (StubHdr.cPackages >= RT_ELEMENTS(aBuildPkgs))
206 {
207 fprintf(stderr, "error: Too many packages specified!\n");
208 return RTEXITCODE_FAILURE;
209 }
210 aBuildPkgs[StubHdr.cPackages].pszSrcPath = pszValue;
211 if (strcmp(pszArg, "-target-all") == 0)
212 aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_ALL;
213 else if (strcmp(pszArg, "-target-amd64") == 0)
214 aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_AMD64;
215 else if (strcmp(pszArg, "-target-arm64") == 0)
216 aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_ARM64;
217 else if (strcmp(pszArg, "-target-x86") == 0)
218 aBuildPkgs[StubHdr.cPackages].enmArch = VBOXSTUBPKGARCH_X86;
219 else
220 {
221 fprintf(stderr, "internal error: %u\n", __LINE__);
222 return RTEXITCODE_FAILURE;
223 }
224 StubHdr.cPackages++;
225 }
226 }
227
228 if (StubHdr.cPackages == 0)
229 {
230 fprintf(stderr, "syntax error: No packages specified! Exiting.\n");
231 return RTEXITCODE_SYNTAX;
232 }
233
234 printf("Stub: %s\n", pszSetupStub);
235 printf("Output: %s\n", pszOutput);
236 printf("# Packages: %u\n", StubHdr.cPackages);
237
238 /*
239 * Copy the stub over the output file.
240 */
241 if (!CopyFile(pszSetupStub, pszOutput, FALSE))
242 {
243 fprintf(stderr, "ERROR: Could not copy the stub loader: %lu\n", GetLastError());
244 return RTEXITCODE_SYNTAX;
245 }
246
247 /*
248 * Start updating the resources of the output file.
249 */
250 HANDLE hUpdate = BeginUpdateResourceA(pszOutput, FALSE);
251 if (hUpdate)
252 {
253 /*
254 * Add the file one by one to the output file.
255 */
256 HRESULT hrc = S_OK;
257 for (BYTE i = 0; i < StubHdr.cPackages; i++)
258 {
259 printf("Integrating (Platform %d): %s\n", aBuildPkgs[i].enmArch, aBuildPkgs[i].pszSrcPath);
260
261 /*
262 * Create the package header.
263 */
264 VBOXSTUBPKG Package = {0};
265 Package.enmArch = aBuildPkgs[i].enmArch;
266
267 /* The resource name */
268 hrc = StringCchPrintf(Package.szResourceName, sizeof(Package.szResourceName), "BIN_%02d", i);
269 if (FAILED(hrc))
270 {
271 fprintf(stderr, "Internal error: %u\n", __LINE__);
272 break;
273 }
274
275 /* Construct final name used when extracting. */
276 hrc = StringCchCopy(Package.szFilename, sizeof(Package.szFilename), MyPathFilename(aBuildPkgs[i].pszSrcPath));
277 if (FAILED(hrc))
278 {
279 fprintf(stderr, "ERROR: Filename is too long: %s\n", aBuildPkgs[i].pszSrcPath);
280 break;
281 }
282
283 /*
284 * Add the package header to the binary.
285 */
286 char szHeaderName[32];
287 hrc = StringCchPrintf(szHeaderName, sizeof(szHeaderName), "HDR_%02d", i);
288 if (FAILED(hrc))
289 {
290 fprintf(stderr, "Internal error: %u\n", __LINE__);
291 break;
292 }
293
294 if (!UpdateResourceA(hUpdate, RT_RCDATA, szHeaderName, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
295 &Package, sizeof(Package)))
296 {
297 fprintf(stderr, "ERROR: UpdateResourceA failed for the package header: %lu\n", GetLastError());
298 hrc = E_FAIL;
299 break;
300 }
301
302 /*
303 * Add the file content under the BIN_xx resource name.
304 */
305 hrc = IntegrateFile(hUpdate, RT_RCDATA, Package.szResourceName, aBuildPkgs[i].pszSrcPath);
306 if (FAILED(hrc))
307 break;
308 }
309 if (SUCCEEDED(hrc))
310 {
311 /*
312 * Now add the header/manifest and complete the operation.
313 */
314 if (UpdateResourceA(hUpdate, RT_RCDATA, "MANIFEST", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
315 &StubHdr, sizeof(StubHdr)))
316 {
317 if (EndUpdateResourceA(hUpdate, FALSE /*fDiscard*/))
318 {
319 printf("Successfully created the installer\n");
320 return RTEXITCODE_SUCCESS;
321 }
322 fprintf(stderr, "ERROR: EndUpdateResourceA failed: %lu\n", GetLastError());
323 }
324 else
325 fprintf(stderr, "ERROR: UpdateResourceA failed for the installer header/manifest: %lu\n", GetLastError());
326 }
327
328 EndUpdateResourceA(hUpdate, TRUE /*fDiscard*/);
329 hUpdate = NULL;
330 }
331 else
332 fprintf(stderr, "error: BeginUpdateResource failed: %lu\n", GetLastError());
333 return RTEXITCODE_FAILURE;
334}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette