VirtualBox

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

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

IPRT/vfs-chains: Pass around an pErrInfo buffer too.

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