VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTManifest.cpp@ 63942

Last change on this file since 63942 was 62570, checked in by vboxsync, 8 years ago

IPRT: More unused parameters.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 KB
Line 
1/* $Id: RTManifest.cpp 62570 2016-07-26 15:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Manifest Utility.
4 */
5
6/*
7 * Copyright (C) 2010-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/manifest.h>
32
33#include <iprt/buildconfig.h>
34#include <iprt/err.h>
35#include <iprt/file.h>
36#include <iprt/getopt.h>
37#include <iprt/initterm.h>
38#include <iprt/message.h>
39#include <iprt/path.h>
40#include <iprt/process.h>
41#include <iprt/stream.h>
42#include <iprt/string.h>
43#include <iprt/vfs.h>
44
45
46/**
47 * Verify a manifest.
48 *
49 * @returns Program exit code, failures with error message.
50 * @param pszManifest The manifest file. NULL if standard input.
51 * @param fStdFormat Whether to expect standard format (true) or
52 * java format (false).
53 * @param pszChDir The directory to change into before processing
54 * the files in the manifest.
55 */
56static RTEXITCODE rtManifestDoVerify(const char *pszManifest, bool fStdFormat, const char *pszChDir)
57{
58 RT_NOREF_PV(pszChDir); /** @todo implement pszChDir! */
59
60 /*
61 * Open the manifest.
62 */
63 int rc;
64 RTVFSIOSTREAM hVfsIos;
65 if (!pszManifest)
66 {
67 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT, RTFILE_O_READ, false /*fLeaveOpen*/, &hVfsIos);
68 if (RT_FAILURE(rc))
69 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to prepare standard input for reading: %Rrc", rc);
70 }
71 else
72 {
73 const char *pszError;
74 rc = RTVfsChainOpenIoStream(pszManifest, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, &hVfsIos, &pszError);
75 if (RT_FAILURE(rc))
76 {
77 if (pszError && *pszError)
78 return RTMsgErrorExit(RTEXITCODE_FAILURE,
79 "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
80 " '%s'\n"
81 " %*s^\n",
82 rc, pszManifest, pszError - pszManifest, "");
83 return RTMsgErrorExit(RTEXITCODE_FAILURE,
84 "Failed with %Rrc opening the input manifest '%s'", rc, pszManifest);
85 }
86 }
87
88 /*
89 * Read it.
90 */
91 RTMANIFEST hManifest;
92 rc = RTManifestCreate(0 /*fFlags*/, &hManifest);
93 if (RT_SUCCESS(rc))
94 {
95 if (fStdFormat)
96 {
97 char szErr[4096 + 1024];
98 rc = RTManifestReadStandardEx(hManifest, hVfsIos, szErr, sizeof(szErr));
99 if (RT_SUCCESS(rc))
100 {
101 RTVfsIoStrmRelease(hVfsIos);
102 hVfsIos = NIL_RTVFSIOSTREAM;
103
104 /*
105 * Do the verification.
106 */
107 /** @todo We're missing some enumeration APIs here! */
108 RTMsgError("The manifest read fine, but the actual verification code is yet to be written. Sorry.");
109 rc = VERR_NOT_IMPLEMENTED;
110#if 1 /* For now, just write the manifest to stdout so we can test the read routine. */
111 RTVFSIOSTREAM hVfsIosOut;
112 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, false /*fLeaveOpen*/, &hVfsIosOut);
113 if (RT_SUCCESS(rc))
114 {
115 RTManifestWriteStandard(hManifest, hVfsIosOut);
116 RTVfsIoStrmRelease(hVfsIosOut);
117 }
118#endif
119 }
120 else if (szErr[0])
121 RTMsgError("Error reading manifest: %s", szErr);
122 else
123 RTMsgError("Error reading manifest: %Rrc", rc);
124 }
125 else
126 {
127 RTMsgError("Support for Java manifest files is not implemented yet");
128 rc = VERR_NOT_IMPLEMENTED;
129 }
130 RTManifestRelease(hManifest);
131 }
132
133 RTVfsIoStrmRelease(hVfsIos);
134 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
135}
136
137
138/**
139 * Adds a file to the manifest.
140 *
141 * @returns IPRT status code, failures with error message.
142 * @param hManifest The manifest to add it to.
143 * @param pszFilename The name of the file to add.
144 * @param fAttr The manifest attributes to add.
145 */
146static int rtManifestAddFileToManifest(RTMANIFEST hManifest, const char *pszFilename, uint32_t fAttr)
147{
148 RTVFSIOSTREAM hVfsIos;
149 const char *pszError;
150 int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, &hVfsIos, &pszError);
151 if (RT_FAILURE(rc))
152 {
153 if (pszError && *pszError)
154 RTMsgError("RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
155 " '%s'\n"
156 " %*s^\n",
157 rc, pszFilename, pszError - pszFilename, "");
158 else
159 RTMsgError("Failed with %Rrc opening '%s'", rc, pszFilename);
160 return rc;
161 }
162
163 rc = RTManifestEntryAddIoStream(hManifest, hVfsIos, pszFilename, fAttr);
164 if (RT_FAILURE(rc))
165 RTMsgError("RTManifestEntryAddIoStream failed for '%s': %Rrc", pszFilename, rc);
166
167 RTVfsIoStrmRelease(hVfsIos);
168 return rc;
169}
170
171
172/**
173 * Create a manifest from the specified input files.
174 *
175 * @returns Program exit code, failures with error message.
176 * @param pszManifest The name of the output manifest file. NULL if
177 * it should be written to standard output.
178 * @param fStdFormat Whether to expect standard format (true) or
179 * java format (false).
180 * @param pszChDir The directory to change into before processing
181 * the file arguments.
182 * @param fAttr The file attributes to put in the manifest.
183 * @param pGetState The RTGetOpt state.
184 * @param pUnion What the last RTGetOpt() call returned.
185 * @param chOpt What the last RTGetOpt() call returned.
186 */
187static RTEXITCODE rtManifestDoCreate(const char *pszManifest, bool fStdFormat, const char *pszChDir, uint32_t fAttr,
188 PRTGETOPTSTATE pGetState, PRTGETOPTUNION pUnion, int chOpt)
189{
190 /*
191 * Open the manifest file.
192 */
193 int rc;
194 RTVFSIOSTREAM hVfsIos;
195 if (!pszManifest)
196 {
197 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, false /*fLeaveOpen*/, &hVfsIos);
198 if (RT_FAILURE(rc))
199 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to prepare standard output for writing: %Rrc", rc);
200 }
201 else
202 {
203 const char *pszError;
204 rc = RTVfsChainOpenIoStream(pszManifest, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
205 &hVfsIos, &pszError);
206 if (RT_FAILURE(rc))
207 {
208 if (pszError && *pszError)
209 return RTMsgErrorExit(RTEXITCODE_FAILURE,
210 "RTVfsChainOpenIoStream failed with rc=%Rrc:\n"
211 " '%s'\n"
212 " %*s^\n",
213 rc, pszManifest, pszError - pszManifest, "");
214 return RTMsgErrorExit(RTEXITCODE_FAILURE,
215 "Failed with %Rrc opening the manifest '%s'", rc, pszManifest);
216 }
217 }
218
219 /*
220 * Create the internal manifest.
221 */
222 RTMANIFEST hManifest;
223 rc = RTManifestCreate(0 /*fFlags*/, &hManifest);
224 if (RT_SUCCESS(rc))
225 {
226 /*
227 * Change directory and start processing the specified files.
228 */
229 if (pszChDir)
230 {
231 rc = RTPathSetCurrent(pszChDir);
232 if (RT_FAILURE(rc))
233 RTMsgError("Failed to change directory to '%s': %Rrc", pszChDir, rc);
234 }
235 if (RT_SUCCESS(rc))
236 {
237 while (chOpt == VINF_GETOPT_NOT_OPTION)
238 {
239 rc = rtManifestAddFileToManifest(hManifest, pUnion->psz, fAttr);
240 if (RT_FAILURE(rc))
241 break;
242
243 /* next */
244 chOpt = RTGetOpt(pGetState, pUnion);
245 }
246 if (RT_SUCCESS(rc) && chOpt != 0)
247 {
248 RTGetOptPrintError(chOpt, pUnion);
249 rc = chOpt < 0 ? chOpt : -chOpt;
250 }
251 }
252
253 /*
254 * Write the manifest.
255 */
256 if (RT_SUCCESS(rc))
257 {
258 if (fStdFormat)
259 {
260 rc = RTManifestWriteStandard(hManifest, hVfsIos);
261 if (RT_FAILURE(rc))
262 RTMsgError("RTManifestWriteStandard failed: %Rrc", rc);
263 }
264 else
265 {
266 RTMsgError("Support for Java manifest files is not implemented yet");
267 rc = VERR_NOT_IMPLEMENTED;
268 }
269 }
270
271 RTManifestRelease(hManifest);
272 }
273
274 RTVfsIoStrmRelease(hVfsIos);
275 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
276}
277
278
279int main(int argc, char **argv)
280{
281 int rc = RTR3InitExe(argc, &argv, 0);
282 if (RT_FAILURE(rc))
283 return RTMsgInitFailure(rc);
284
285 /*
286 * Parse arguments.
287 */
288 static RTGETOPTDEF const s_aOptions[] =
289 {
290 { "--manifest", 'm', RTGETOPT_REQ_STRING },
291 { "--java", 'j', RTGETOPT_REQ_NOTHING },
292 { "--chdir", 'C', RTGETOPT_REQ_STRING },
293 { "--attribute", 'a', RTGETOPT_REQ_STRING },
294 { "--verify", 'v', RTGETOPT_REQ_NOTHING },
295 };
296
297 bool fVerify = false;
298 bool fStdFormat = true;
299 const char *pszManifest = NULL;
300 const char *pszChDir = NULL;
301 uint32_t fAttr = RTMANIFEST_ATTR_UNKNOWN;
302
303 RTGETOPTSTATE GetState;
304 rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
305 if (RT_FAILURE(rc))
306 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc", rc);
307
308 RTGETOPTUNION ValueUnion;
309 while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
310 && rc != VINF_GETOPT_NOT_OPTION)
311 {
312 switch (rc)
313 {
314 case 'a':
315 {
316 static struct
317 {
318 const char *pszAttr;
319 uint32_t fAttr;
320 } s_aAttributes[] =
321 {
322 { "size", RTMANIFEST_ATTR_SIZE },
323 { "md5", RTMANIFEST_ATTR_MD5 },
324 { "sha1", RTMANIFEST_ATTR_SHA1 },
325 { "sha256", RTMANIFEST_ATTR_SHA256 },
326 { "sha512", RTMANIFEST_ATTR_SHA512 }
327 };
328 uint32_t fThisAttr = RTMANIFEST_ATTR_UNKNOWN;
329 for (unsigned i = 0; i < RT_ELEMENTS(s_aAttributes); i++)
330 if (!RTStrICmp(s_aAttributes[i].pszAttr, ValueUnion.psz))
331 {
332 fThisAttr = s_aAttributes[i].fAttr;
333 break;
334 }
335 if (fThisAttr == RTMANIFEST_ATTR_UNKNOWN)
336 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown attribute type '%s'", ValueUnion.psz);
337
338 if (fAttr == RTMANIFEST_ATTR_UNKNOWN)
339 fAttr = fThisAttr;
340 else
341 fAttr |= fThisAttr;
342 break;
343 }
344
345 case 'j':
346 fStdFormat = false;
347 break;
348
349 case 'm':
350 if (pszManifest)
351 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Only one manifest can be specified");
352 pszManifest = ValueUnion.psz;
353 break;
354
355 case 'v':
356 fVerify = true;
357 break;
358
359 case 'C':
360 if (pszChDir)
361 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Only one directory change can be specified");
362 pszChDir = ValueUnion.psz;
363 break;
364
365 case 'h':
366 RTPrintf("Usage: %s [--manifest <file>] [--chdir <dir>] [--attribute <attrib-name> [..]] <files>\n"
367 " or %s --verify [--manifest <file>] [--chdir <dir>]\n"
368 "\n"
369 "attrib-name: size, md5, sha1, sha256 or sha512\n"
370 , RTProcShortName(), RTProcShortName());
371 return RTEXITCODE_SUCCESS;
372
373#ifndef IN_BLD_PROG /* RTBldCfgVersion or RTBldCfgRevision in build time IPRT lib. */
374 case 'V':
375 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
376 return RTEXITCODE_SUCCESS;
377#endif
378
379 default:
380 return RTGetOptPrintError(rc, &ValueUnion);
381 }
382 }
383
384 /*
385 * Take action.
386 */
387 RTEXITCODE rcExit;
388 if (!fVerify)
389 {
390 if (rc != VINF_GETOPT_NOT_OPTION)
391 RTMsgWarning("No files specified, the manifest will be empty.");
392 if (fAttr == RTMANIFEST_ATTR_UNKNOWN)
393 fAttr = RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_MD5
394 | RTMANIFEST_ATTR_SHA1 | RTMANIFEST_ATTR_SHA256 | RTMANIFEST_ATTR_SHA512;
395 rcExit = rtManifestDoCreate(pszManifest, fStdFormat, pszChDir, fAttr, &GetState, &ValueUnion, rc);
396 }
397 else
398 {
399 if (rc == VINF_GETOPT_NOT_OPTION)
400 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
401 "No files should be specified when verifying a manifest (--verfiy), "
402 "only a manifest via the --manifest option");
403 if (fAttr != RTMANIFEST_ATTR_UNKNOWN)
404 return RTMsgErrorExit(RTEXITCODE_SYNTAX,
405 "The --attribute (-a) option does not combine with --verify (-v)");
406
407
408 rcExit = rtManifestDoVerify(pszManifest, fStdFormat, pszChDir);
409 }
410
411 return rcExit;
412}
413
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