VirtualBox

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

Last change on this file since 34464 was 34464, checked in by vboxsync, 14 years ago

IPRT: Added a RTManifest tool for testing the new manifest code. Moved the tools out of testcase/ and into tools/.

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

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