VirtualBox

source: vbox/trunk/src/VBox/Storage/testcase/vbox-img.cpp@ 40821

Last change on this file since 40821 was 40821, checked in by vboxsync, 13 years ago

vbox-img: Fix hang when using stdin and the producer in the pipe aborts with an error

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.9 KB
Line 
1/* $Id: vbox-img.cpp 40821 2012-04-07 21:15:33Z vboxsync $ */
2/** @file
3 * Standalone image manipulation tool
4 */
5
6/*
7 * Copyright (C) 2010-2011 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
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <VBox/vd.h>
22#include <VBox/err.h>
23#include <VBox/version.h>
24#include <iprt/initterm.h>
25#include <iprt/buildconfig.h>
26#include <iprt/path.h>
27#include <iprt/string.h>
28#include <iprt/uuid.h>
29#include <iprt/stream.h>
30#include <iprt/message.h>
31#include <iprt/getopt.h>
32#include <iprt/assert.h>
33
34const char *g_pszProgName = "";
35static void printUsage(PRTSTREAM pStrm)
36{
37 RTStrmPrintf(pStrm,
38 "Usage: %s\n"
39 " setuuid --filename <filename>\n"
40 " [--format VDI|VMDK|VHD|...]\n"
41 " [--uuid <uuid>]\n"
42 " [--parentuuid <uuid>]\n"
43 " [--zeroparentuuid]\n"
44 "\n"
45 " convert --srcfilename <filename>\n"
46 " --dstfilename <filename>\n"
47 " [--stdin]|[--stdout]\n"
48 " [--srcformat VDI|VMDK|VHD|RAW|..]\n"
49 " [--dstformat VDI|VMDK|VHD|RAW|..]\n"
50 " [--variant Standard,Fixed,Split2G,Stream,ESX]\n"
51 "\n"
52 " info --filename <filename>\n"
53 "\n"
54 " compact --filename <filename>\n"
55 "\n"
56 " createcache --filename <filename>\n"
57 " --size <cache size>\n"
58 "\n"
59 " createbase --filename <filename>\n"
60 " --size <size in bytes>\n"
61 " [--format VDI|VMDK|VHD] (default: VDI)\n"
62 " [--variant Standard,Fixed,Split2G,Stream,ESX]\n"
63 "\n"
64 " repair --filename <filename>\n"
65 " [--dry-run]\n"
66 " [--format VDI|VMDK|VHD] (default: autodetect)\n",
67 g_pszProgName);
68}
69
70void showLogo(PRTSTREAM pStrm)
71{
72 static bool s_fShown; /* show only once */
73
74 if (!s_fShown)
75 {
76 RTStrmPrintf(pStrm, VBOX_PRODUCT " Disk Utility " VBOX_VERSION_STRING "\n"
77 "(C) 2005-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
78 "All rights reserved.\n"
79 "\n");
80 s_fShown = true;
81 }
82}
83
84/** command handler argument */
85struct HandlerArg
86{
87 int argc;
88 char **argv;
89};
90
91PVDINTERFACE pVDIfs;
92
93static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL,
94 const char *pszFormat, va_list va)
95{
96 NOREF(pvUser);
97 NOREF(rc);
98 RTMsgErrorV(pszFormat, va);
99}
100
101static int handleVDMessage(void *pvUser, const char *pszFormat, va_list va)
102{
103 NOREF(pvUser);
104 RTPrintfV(pszFormat, va);
105 return VINF_SUCCESS;
106}
107
108/**
109 * Print a usage synopsis and the syntax error message.
110 */
111int errorSyntax(const char *pszFormat, ...)
112{
113 va_list args;
114 showLogo(g_pStdErr); // show logo even if suppressed
115 va_start(args, pszFormat);
116 RTStrmPrintf(g_pStdErr, "\nSyntax error: %N\n", pszFormat, &args);
117 va_end(args);
118 printUsage(g_pStdErr);
119 return 1;
120}
121
122int errorRuntime(const char *pszFormat, ...)
123{
124 va_list args;
125
126 va_start(args, pszFormat);
127 RTMsgErrorV(pszFormat, args);
128 va_end(args);
129 return 1;
130}
131
132static int parseDiskVariant(const char *psz, unsigned *puImageFlags)
133{
134 int rc = VINF_SUCCESS;
135 unsigned uImageFlags = *puImageFlags;
136
137 while (psz && *psz && RT_SUCCESS(rc))
138 {
139 size_t len;
140 const char *pszComma = strchr(psz, ',');
141 if (pszComma)
142 len = pszComma - psz;
143 else
144 len = strlen(psz);
145 if (len > 0)
146 {
147 /*
148 * Parsing is intentionally inconsistent: "standard" resets the
149 * variant, whereas the other flags are cumulative.
150 */
151 if (!RTStrNICmp(psz, "standard", len))
152 uImageFlags = VD_IMAGE_FLAGS_NONE;
153 else if ( !RTStrNICmp(psz, "fixed", len)
154 || !RTStrNICmp(psz, "static", len))
155 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
156 else if (!RTStrNICmp(psz, "Diff", len))
157 uImageFlags |= VD_IMAGE_FLAGS_DIFF;
158 else if (!RTStrNICmp(psz, "split2g", len))
159 uImageFlags |= VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
160 else if ( !RTStrNICmp(psz, "stream", len)
161 || !RTStrNICmp(psz, "streamoptimized", len))
162 uImageFlags |= VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED;
163 else if (!RTStrNICmp(psz, "esx", len))
164 uImageFlags |= VD_VMDK_IMAGE_FLAGS_ESX;
165 else
166 rc = VERR_PARSE_ERROR;
167 }
168 if (pszComma)
169 psz += len + 1;
170 else
171 psz += len;
172 }
173
174 if (RT_SUCCESS(rc))
175 *puImageFlags = uImageFlags;
176 return rc;
177}
178
179
180int handleSetUUID(HandlerArg *a)
181{
182 const char *pszFilename = NULL;
183 char *pszFormat = NULL;
184 VDTYPE enmType = VDTYPE_INVALID;
185 RTUUID imageUuid;
186 RTUUID parentUuid;
187 bool fSetImageUuid = false;
188 bool fSetParentUuid = false;
189 RTUuidClear(&imageUuid);
190 RTUuidClear(&parentUuid);
191 int rc;
192
193 /* Parse the command line. */
194 static const RTGETOPTDEF s_aOptions[] =
195 {
196 { "--filename", 'f', RTGETOPT_REQ_STRING },
197 { "--format", 'o', RTGETOPT_REQ_STRING },
198 { "--uuid", 'u', RTGETOPT_REQ_UUID },
199 { "--parentuuid", 'p', RTGETOPT_REQ_UUID },
200 { "--zeroparentuuid", 'P', RTGETOPT_REQ_NOTHING }
201 };
202 int ch;
203 RTGETOPTUNION ValueUnion;
204 RTGETOPTSTATE GetState;
205 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
206 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
207 {
208 switch (ch)
209 {
210 case 'f': // --filename
211 pszFilename = ValueUnion.psz;
212 break;
213 case 'o': // --format
214 pszFormat = RTStrDup(ValueUnion.psz);
215 break;
216 case 'u': // --uuid
217 imageUuid = ValueUnion.Uuid;
218 fSetImageUuid = true;
219 break;
220 case 'p': // --parentuuid
221 parentUuid = ValueUnion.Uuid;
222 fSetParentUuid = true;
223 break;
224 case 'P': // --zeroparentuuid
225 RTUuidClear(&parentUuid);
226 fSetParentUuid = true;
227 break;
228
229 default:
230 ch = RTGetOptPrintError(ch, &ValueUnion);
231 printUsage(g_pStdErr);
232 return ch;
233 }
234 }
235
236 /* Check for mandatory parameters. */
237 if (!pszFilename)
238 return errorSyntax("Mandatory --filename option missing\n");
239
240 /* Check for consistency of optional parameters. */
241 if (fSetImageUuid && RTUuidIsNull(&imageUuid))
242 return errorSyntax("Invalid parameter to --uuid option\n");
243
244 /* Autodetect image format. */
245 if (!pszFormat)
246 {
247 /* Don't pass error interface, as that would triggers error messages
248 * because some backends fail to open the image. */
249 rc = VDGetFormat(NULL, NULL, pszFilename, &pszFormat, &enmType);
250 if (RT_FAILURE(rc))
251 return errorRuntime("Format autodetect failed: %Rrc\n", rc);
252 }
253
254 PVBOXHDD pVD = NULL;
255 rc = VDCreate(pVDIfs, enmType, &pVD);
256 if (RT_FAILURE(rc))
257 return errorRuntime("Cannot create the virtual disk container: %Rrc\n", rc);
258
259
260 rc = VDOpen(pVD, pszFormat, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
261 if (RT_FAILURE(rc))
262 return errorRuntime("Cannot open the virtual disk image \"%s\": %Rrc\n",
263 pszFilename, rc);
264
265 RTUUID oldImageUuid;
266 rc = VDGetUuid(pVD, VD_LAST_IMAGE, &oldImageUuid);
267 if (RT_FAILURE(rc))
268 return errorRuntime("Cannot get UUID of virtual disk image \"%s\": %Rrc\n",
269 pszFilename, rc);
270
271 RTPrintf("Old image UUID: %RTuuid\n", &oldImageUuid);
272
273 RTUUID oldParentUuid;
274 rc = VDGetParentUuid(pVD, VD_LAST_IMAGE, &oldParentUuid);
275 if (RT_FAILURE(rc))
276 return errorRuntime("Cannot get parent UUID of virtual disk image \"%s\": %Rrc\n",
277 pszFilename, rc);
278
279 RTPrintf("Old parent UUID: %RTuuid\n", &oldParentUuid);
280
281 if (fSetImageUuid)
282 {
283 RTPrintf("New image UUID: %RTuuid\n", &imageUuid);
284 rc = VDSetUuid(pVD, VD_LAST_IMAGE, &imageUuid);
285 if (RT_FAILURE(rc))
286 return errorRuntime("Cannot set UUID of virtual disk image \"%s\": %Rrc\n",
287 pszFilename, rc);
288 }
289
290 if (fSetParentUuid)
291 {
292 RTPrintf("New parent UUID: %RTuuid\n", &parentUuid);
293 rc = VDSetParentUuid(pVD, VD_LAST_IMAGE, &parentUuid);
294 if (RT_FAILURE(rc))
295 return errorRuntime("Cannot set parent UUID of virtual disk image \"%s\": %Rrc\n",
296 pszFilename, rc);
297 }
298
299 VDDestroy(pVD);
300
301 if (pszFormat)
302 {
303 RTStrFree(pszFormat);
304 pszFormat = NULL;
305 }
306
307 return 0;
308}
309
310
311typedef struct FILEIOSTATE
312{
313 RTFILE file;
314 /** Offset in the file. */
315 uint64_t off;
316 /** Offset where the buffer contents start. UINT64_MAX=buffer invalid. */
317 uint64_t offBuffer;
318 /** Size of valid data in the buffer. */
319 uint32_t cbBuffer;
320 /** Buffer for efficient I/O */
321 uint8_t abBuffer[16 *_1M];
322} FILEIOSTATE, *PFILEIOSTATE;
323
324static int convInOpen(void *pvUser, const char *pszLocation,
325 uint32_t fOpen, PFNVDCOMPLETED pfnCompleted,
326 void **ppStorage)
327{
328 NOREF(pvUser);
329 /* Validate input. */
330 AssertPtrReturn(ppStorage, VERR_INVALID_POINTER);
331 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
332 AssertReturn((fOpen & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ, VERR_INVALID_PARAMETER);
333 RTFILE file;
334 int rc = RTFileFromNative(&file, RTFILE_NATIVE_STDIN);
335 if (RT_FAILURE(rc))
336 return rc;
337
338 /* No need to clear the buffer, the data will be read from disk. */
339 PFILEIOSTATE pFS = (PFILEIOSTATE)RTMemAlloc(sizeof(FILEIOSTATE));
340 if (!pFS)
341 return VERR_NO_MEMORY;
342
343 pFS->file = file;
344 pFS->off = 0;
345 pFS->offBuffer = UINT64_MAX;
346 pFS->cbBuffer = 0;
347
348 *ppStorage = pFS;
349 return VINF_SUCCESS;
350}
351
352static int convInClose(void *pvUser, void *pStorage)
353{
354 NOREF(pvUser);
355 AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
356 PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
357
358 RTMemFree(pFS);
359
360 return VINF_SUCCESS;
361}
362
363static int convInDelete(void *pvUser, const char *pcszFilename)
364{
365 NOREF(pvUser);
366 NOREF(pcszFilename);
367 AssertFailedReturn(VERR_NOT_SUPPORTED);
368}
369
370static int convInMove(void *pvUser, const char *pcszSrc, const char *pcszDst,
371 unsigned fMove)
372{
373 NOREF(pvUser);
374 NOREF(pcszSrc);
375 NOREF(pcszDst);
376 NOREF(fMove);
377 AssertFailedReturn(VERR_NOT_SUPPORTED);
378}
379
380static int convInGetFreeSpace(void *pvUser, const char *pcszFilename,
381 int64_t *pcbFreeSpace)
382{
383 NOREF(pvUser);
384 NOREF(pcszFilename);
385 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
386 *pcbFreeSpace = 0;
387 return VINF_SUCCESS;
388}
389
390static int convInGetModificationTime(void *pvUser, const char *pcszFilename,
391 PRTTIMESPEC pModificationTime)
392{
393 NOREF(pvUser);
394 NOREF(pcszFilename);
395 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
396 AssertFailedReturn(VERR_NOT_SUPPORTED);
397}
398
399static int convInGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
400{
401 NOREF(pvUser);
402 NOREF(pStorage);
403 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
404 AssertFailedReturn(VERR_NOT_SUPPORTED);
405}
406
407static int convInSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
408{
409 NOREF(pvUser);
410 NOREF(pStorage);
411 NOREF(cbSize);
412 AssertFailedReturn(VERR_NOT_SUPPORTED);
413}
414
415static int convInRead(void *pvUser, void *pStorage, uint64_t uOffset,
416 void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
417{
418 NOREF(pvUser);
419 AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
420 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
421 PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
422 AssertReturn(uOffset >= pFS->off, VERR_INVALID_PARAMETER);
423 int rc;
424
425 /* Fill buffer if it is empty. */
426 if (pFS->offBuffer == UINT64_MAX)
427 {
428 /* Repeat reading until buffer is full or EOF. */
429 size_t cbSumRead = 0, cbRead;
430 uint8_t *pTmp = (uint8_t *)&pFS->abBuffer[0];
431 size_t cbTmp = sizeof(pFS->abBuffer);
432 do
433 {
434 rc = RTFileRead(pFS->file, pTmp, cbTmp, &cbRead);
435 if (RT_FAILURE(rc))
436 return rc;
437 pTmp += cbRead;
438 cbTmp -= cbRead;
439 cbSumRead += cbRead;
440 } while (cbTmp && cbRead);
441
442 pFS->offBuffer = 0;
443 pFS->cbBuffer = cbSumRead;
444 if (!cbSumRead && !pcbRead) /* Caller can't handle partial reads. */
445 return VERR_EOF;
446 }
447
448 /* Read several blocks and assemble the result if necessary */
449 size_t cbTotalRead = 0;
450 do
451 {
452 /* Skip over areas no one wants to read. */
453 while (uOffset > pFS->offBuffer + pFS->cbBuffer - 1)
454 {
455 if (pFS->cbBuffer < sizeof(pFS->abBuffer))
456 {
457 if (pcbRead)
458 *pcbRead = cbTotalRead;
459 return VERR_EOF;
460 }
461
462 /* Repeat reading until buffer is full or EOF. */
463 size_t cbSumRead = 0, cbRead;
464 uint8_t *pTmp = (uint8_t *)&pFS->abBuffer[0];
465 size_t cbTmp = sizeof(pFS->abBuffer);
466 do
467 {
468 rc = RTFileRead(pFS->file, pTmp, cbTmp, &cbRead);
469 if (RT_FAILURE(rc))
470 return rc;
471 pTmp += cbRead;
472 cbTmp -= cbRead;
473 cbSumRead += cbRead;
474 } while (cbTmp && cbRead);
475
476 pFS->offBuffer += pFS->cbBuffer;
477 pFS->cbBuffer = cbSumRead;
478 }
479
480 uint32_t cbThisRead = RT_MIN(cbBuffer,
481 pFS->cbBuffer - uOffset % sizeof(pFS->abBuffer));
482 memcpy(pvBuffer, &pFS->abBuffer[uOffset % sizeof(pFS->abBuffer)],
483 cbThisRead);
484 uOffset += cbThisRead;
485 pvBuffer = (uint8_t *)pvBuffer + cbThisRead;
486 cbBuffer -= cbThisRead;
487 cbTotalRead += cbThisRead;
488 if (!cbTotalRead && !pcbRead) /* Caller can't handle partial reads. */
489 return VERR_EOF;
490 } while (cbBuffer > 0);
491
492 if (pcbRead)
493 *pcbRead = cbTotalRead;
494
495 pFS->off = uOffset;
496
497 return VINF_SUCCESS;
498}
499
500static int convInWrite(void *pvUser, void *pStorage, uint64_t uOffset,
501 const void *pvBuffer, size_t cbBuffer,
502 size_t *pcbWritten)
503{
504 NOREF(pvUser);
505 NOREF(pStorage);
506 NOREF(uOffset);
507 NOREF(cbBuffer);
508 NOREF(pcbWritten);
509 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
510 AssertFailedReturn(VERR_NOT_SUPPORTED);
511}
512
513static int convInFlush(void *pvUser, void *pStorage)
514{
515 NOREF(pvUser);
516 NOREF(pStorage);
517 return VINF_SUCCESS;
518}
519
520static int convOutOpen(void *pvUser, const char *pszLocation,
521 uint32_t fOpen, PFNVDCOMPLETED pfnCompleted,
522 void **ppStorage)
523{
524 NOREF(pvUser);
525 /* Validate input. */
526 AssertPtrReturn(ppStorage, VERR_INVALID_POINTER);
527 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
528 AssertReturn((fOpen & RTFILE_O_ACCESS_MASK) == RTFILE_O_WRITE, VERR_INVALID_PARAMETER);
529 RTFILE file;
530 int rc = RTFileFromNative(&file, RTFILE_NATIVE_STDOUT);
531 if (RT_FAILURE(rc))
532 return rc;
533
534 /* Must clear buffer, so that skipped over data is initialized properly. */
535 PFILEIOSTATE pFS = (PFILEIOSTATE)RTMemAllocZ(sizeof(FILEIOSTATE));
536 if (!pFS)
537 return VERR_NO_MEMORY;
538
539 pFS->file = file;
540 pFS->off = 0;
541 pFS->offBuffer = 0;
542 pFS->cbBuffer = sizeof(FILEIOSTATE);
543
544 *ppStorage = pFS;
545 return VINF_SUCCESS;
546}
547
548static int convOutClose(void *pvUser, void *pStorage)
549{
550 NOREF(pvUser);
551 AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
552 PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
553 int rc = VINF_SUCCESS;
554
555 /* Flush any remaining buffer contents. */
556 if (pFS->cbBuffer)
557 rc = RTFileWrite(pFS->file, &pFS->abBuffer[0], pFS->cbBuffer, NULL);
558
559 RTMemFree(pFS);
560
561 return rc;
562}
563
564static int convOutDelete(void *pvUser, const char *pcszFilename)
565{
566 NOREF(pvUser);
567 NOREF(pcszFilename);
568 AssertFailedReturn(VERR_NOT_SUPPORTED);
569}
570
571static int convOutMove(void *pvUser, const char *pcszSrc, const char *pcszDst,
572 unsigned fMove)
573{
574 NOREF(pvUser);
575 NOREF(pcszSrc);
576 NOREF(pcszDst);
577 NOREF(fMove);
578 AssertFailedReturn(VERR_NOT_SUPPORTED);
579}
580
581static int convOutGetFreeSpace(void *pvUser, const char *pcszFilename,
582 int64_t *pcbFreeSpace)
583{
584 NOREF(pvUser);
585 NOREF(pcszFilename);
586 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
587 *pcbFreeSpace = INT64_MAX;
588 return VINF_SUCCESS;
589}
590
591static int convOutGetModificationTime(void *pvUser, const char *pcszFilename,
592 PRTTIMESPEC pModificationTime)
593{
594 NOREF(pvUser);
595 NOREF(pcszFilename);
596 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
597 AssertFailedReturn(VERR_NOT_SUPPORTED);
598}
599
600static int convOutGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
601{
602 NOREF(pvUser);
603 NOREF(pStorage);
604 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
605 AssertFailedReturn(VERR_NOT_SUPPORTED);
606}
607
608static int convOutSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
609{
610 NOREF(pvUser);
611 NOREF(pStorage);
612 NOREF(cbSize);
613 AssertFailedReturn(VERR_NOT_SUPPORTED);
614}
615
616static int convOutRead(void *pvUser, void *pStorage, uint64_t uOffset,
617 void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
618{
619 NOREF(pvUser);
620 NOREF(pStorage);
621 NOREF(uOffset);
622 NOREF(cbBuffer);
623 NOREF(pcbRead);
624 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
625 AssertFailedReturn(VERR_NOT_SUPPORTED);
626}
627
628static int convOutWrite(void *pvUser, void *pStorage, uint64_t uOffset,
629 const void *pvBuffer, size_t cbBuffer,
630 size_t *pcbWritten)
631{
632 NOREF(pvUser);
633 AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
634 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
635 PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
636 AssertReturn(uOffset >= pFS->off, VERR_INVALID_PARAMETER);
637 int rc;
638
639 /* Write the data to the buffer, flushing as required. */
640 size_t cbTotalWritten = 0;
641 do
642 {
643 /* Flush the buffer if we need a new one. */
644 while (uOffset > pFS->offBuffer + sizeof(pFS->abBuffer) - 1)
645 {
646 rc = RTFileWrite(pFS->file, &pFS->abBuffer[0],
647 sizeof(pFS->abBuffer), NULL);
648 RT_ZERO(pFS->abBuffer);
649 pFS->offBuffer += sizeof(pFS->abBuffer);
650 pFS->cbBuffer = 0;
651 }
652
653 uint32_t cbThisWrite = RT_MIN(cbBuffer,
654 sizeof(pFS->abBuffer) - uOffset % sizeof(pFS->abBuffer));
655 memcpy(&pFS->abBuffer[uOffset % sizeof(pFS->abBuffer)], pvBuffer,
656 cbThisWrite);
657 uOffset += cbThisWrite;
658 pvBuffer = (uint8_t *)pvBuffer + cbThisWrite;
659 cbBuffer -= cbThisWrite;
660 cbTotalWritten += cbThisWrite;
661 } while (cbBuffer > 0);
662
663 if (pcbWritten)
664 *pcbWritten = cbTotalWritten;
665
666 pFS->cbBuffer = uOffset % sizeof(pFS->abBuffer);
667 if (!pFS->cbBuffer)
668 pFS->cbBuffer = sizeof(pFS->abBuffer);
669 pFS->off = uOffset;
670
671 return VINF_SUCCESS;
672}
673
674static int convOutFlush(void *pvUser, void *pStorage)
675{
676 NOREF(pvUser);
677 NOREF(pStorage);
678 return VINF_SUCCESS;
679}
680
681int handleConvert(HandlerArg *a)
682{
683 const char *pszSrcFilename = NULL;
684 const char *pszDstFilename = NULL;
685 bool fStdIn = false;
686 bool fStdOut = false;
687 const char *pszSrcFormat = NULL;
688 VDTYPE enmSrcType = VDTYPE_HDD;
689 const char *pszDstFormat = NULL;
690 const char *pszVariant = NULL;
691 PVBOXHDD pSrcDisk = NULL;
692 PVBOXHDD pDstDisk = NULL;
693 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
694 PVDINTERFACE pIfsImageInput = NULL;
695 PVDINTERFACE pIfsImageOutput = NULL;
696 VDINTERFACEIO IfsInputIO;
697 VDINTERFACEIO IfsOutputIO;
698 int rc = VINF_SUCCESS;
699
700 /* Parse the command line. */
701 static const RTGETOPTDEF s_aOptions[] =
702 {
703 { "--srcfilename", 'i', RTGETOPT_REQ_STRING },
704 { "--dstfilename", 'o', RTGETOPT_REQ_STRING },
705 { "--stdin", 'p', RTGETOPT_REQ_NOTHING },
706 { "--stdout", 'P', RTGETOPT_REQ_NOTHING },
707 { "--srcformat", 's', RTGETOPT_REQ_STRING },
708 { "--dstformat", 'd', RTGETOPT_REQ_STRING },
709 { "--variant", 'v', RTGETOPT_REQ_STRING }
710 };
711 int ch;
712 RTGETOPTUNION ValueUnion;
713 RTGETOPTSTATE GetState;
714 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
715 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
716 {
717 switch (ch)
718 {
719 case 'i': // --srcfilename
720 pszSrcFilename = ValueUnion.psz;
721 break;
722 case 'o': // --dstfilename
723 pszDstFilename = ValueUnion.psz;
724 break;
725 case 'p': // --stdin
726 fStdIn = true;
727 break;
728 case 'P': // --stdout
729 fStdOut = true;
730 break;
731 case 's': // --srcformat
732 pszSrcFormat = ValueUnion.psz;
733 break;
734 case 'd': // --dstformat
735 pszDstFormat = ValueUnion.psz;
736 break;
737 case 'v': // --variant
738 pszVariant = ValueUnion.psz;
739 break;
740
741 default:
742 ch = RTGetOptPrintError(ch, &ValueUnion);
743 printUsage(g_pStdErr);
744 return ch;
745 }
746 }
747
748 /* Check for mandatory parameters and handle dummies/defaults. */
749 if (fStdIn && !pszSrcFormat)
750 return errorSyntax("Mandatory --srcformat option missing\n");
751 if (!pszDstFormat)
752 pszDstFormat = "VDI";
753 if (fStdIn && !pszSrcFilename)
754 {
755 /* Complete dummy, will be just passed to various calls to fulfill
756 * the "must be non-NULL" requirement, and is completely ignored
757 * otherwise. It shown in the stderr message below. */
758 pszSrcFilename = "stdin";
759 }
760 if (fStdOut && !pszDstFilename)
761 {
762 /* Will be stored in the destination image if it is a streamOptimized
763 * VMDK, but it isn't really relevant - use it for "branding". */
764 if (!RTStrICmp(pszDstFormat, "VMDK"))
765 pszDstFilename = "VirtualBoxStream.vmdk";
766 else
767 pszDstFilename = "stdout";
768 }
769 if (!pszSrcFilename)
770 return errorSyntax("Mandatory --srcfilename option missing\n");
771 if (!pszDstFilename)
772 return errorSyntax("Mandatory --dstfilename option missing\n");
773
774 if (fStdIn)
775 {
776 IfsInputIO.pfnOpen = convInOpen;
777 IfsInputIO.pfnClose = convInClose;
778 IfsInputIO.pfnDelete = convInDelete;
779 IfsInputIO.pfnMove = convInMove;
780 IfsInputIO.pfnGetFreeSpace = convInGetFreeSpace;
781 IfsInputIO.pfnGetModificationTime = convInGetModificationTime;
782 IfsInputIO.pfnGetSize = convInGetSize;
783 IfsInputIO.pfnSetSize = convInSetSize;
784 IfsInputIO.pfnReadSync = convInRead;
785 IfsInputIO.pfnWriteSync = convInWrite;
786 IfsInputIO.pfnFlushSync = convInFlush;
787 VDInterfaceAdd(&IfsInputIO.Core, "stdin", VDINTERFACETYPE_IO,
788 NULL, sizeof(VDINTERFACEIO), &pIfsImageInput);
789 }
790 if (fStdOut)
791 {
792 IfsOutputIO.pfnOpen = convOutOpen;
793 IfsOutputIO.pfnClose = convOutClose;
794 IfsOutputIO.pfnDelete = convOutDelete;
795 IfsOutputIO.pfnMove = convOutMove;
796 IfsOutputIO.pfnGetFreeSpace = convOutGetFreeSpace;
797 IfsOutputIO.pfnGetModificationTime = convOutGetModificationTime;
798 IfsOutputIO.pfnGetSize = convOutGetSize;
799 IfsOutputIO.pfnSetSize = convOutSetSize;
800 IfsOutputIO.pfnReadSync = convOutRead;
801 IfsOutputIO.pfnWriteSync = convOutWrite;
802 IfsOutputIO.pfnFlushSync = convOutFlush;
803 VDInterfaceAdd(&IfsOutputIO.Core, "stdout", VDINTERFACETYPE_IO,
804 NULL, sizeof(VDINTERFACEIO), &pIfsImageOutput);
805 }
806
807 /* check the variant parameter */
808 if (pszVariant)
809 {
810 char *psz = (char*)pszVariant;
811 while (psz && *psz && RT_SUCCESS(rc))
812 {
813 size_t len;
814 const char *pszComma = strchr(psz, ',');
815 if (pszComma)
816 len = pszComma - psz;
817 else
818 len = strlen(psz);
819 if (len > 0)
820 {
821 if (!RTStrNICmp(pszVariant, "standard", len))
822 uImageFlags |= VD_IMAGE_FLAGS_NONE;
823 else if (!RTStrNICmp(pszVariant, "fixed", len))
824 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
825 else if (!RTStrNICmp(pszVariant, "split2g", len))
826 uImageFlags |= VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
827 else if (!RTStrNICmp(pszVariant, "stream", len))
828 uImageFlags |= VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED;
829 else if (!RTStrNICmp(pszVariant, "esx", len))
830 uImageFlags |= VD_VMDK_IMAGE_FLAGS_ESX;
831 else
832 return errorSyntax("Invalid --variant option\n");
833 }
834 if (pszComma)
835 psz += len + 1;
836 else
837 psz += len;
838 }
839 }
840
841 do
842 {
843 /* try to determine input format if not specified */
844 if (!pszSrcFormat)
845 {
846 char *pszFormat = NULL;
847 VDTYPE enmType = VDTYPE_INVALID;
848 rc = VDGetFormat(NULL, NULL, pszSrcFilename, &pszFormat, &enmType);
849 if (RT_FAILURE(rc))
850 {
851 errorSyntax("No file format specified, please specify format: %Rrc\n", rc);
852 break;
853 }
854 pszSrcFormat = pszFormat;
855 enmSrcType = enmType;
856 }
857
858 rc = VDCreate(pVDIfs, enmSrcType, &pSrcDisk);
859 if (RT_FAILURE(rc))
860 {
861 errorRuntime("Error while creating source disk container: %Rrc\n", rc);
862 break;
863 }
864
865 rc = VDOpen(pSrcDisk, pszSrcFormat, pszSrcFilename,
866 VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SEQUENTIAL,
867 pIfsImageInput);
868 if (RT_FAILURE(rc))
869 {
870 errorRuntime("Error while opening source image: %Rrc\n", rc);
871 break;
872 }
873
874 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDstDisk);
875 if (RT_FAILURE(rc))
876 {
877 errorRuntime("Error while creating the destination disk container: %Rrc\n", rc);
878 break;
879 }
880
881 uint64_t cbSize = VDGetSize(pSrcDisk, VD_LAST_IMAGE);
882 RTStrmPrintf(g_pStdErr, "Converting image \"%s\" with size %RU64 bytes (%RU64MB)...\n", pszSrcFilename, cbSize, (cbSize + _1M - 1) / _1M);
883
884 /* Create the output image */
885 rc = VDCopy(pSrcDisk, VD_LAST_IMAGE, pDstDisk, pszDstFormat,
886 pszDstFilename, false, 0, uImageFlags, NULL,
887 VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_SEQUENTIAL, NULL,
888 pIfsImageOutput, NULL);
889 if (RT_FAILURE(rc))
890 {
891 errorRuntime("Error while copying the image: %Rrc\n", rc);
892 break;
893 }
894
895 }
896 while (0);
897
898 if (pDstDisk)
899 VDDestroy(pDstDisk);
900 if (pSrcDisk)
901 VDDestroy(pSrcDisk);
902
903 return RT_SUCCESS(rc) ? 0 : 1;
904}
905
906
907int handleInfo(HandlerArg *a)
908{
909 int rc = VINF_SUCCESS;
910 PVBOXHDD pDisk = NULL;
911 const char *pszFilename = NULL;
912
913 /* Parse the command line. */
914 static const RTGETOPTDEF s_aOptions[] =
915 {
916 { "--filename", 'f', RTGETOPT_REQ_STRING }
917 };
918 int ch;
919 RTGETOPTUNION ValueUnion;
920 RTGETOPTSTATE GetState;
921 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
922 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
923 {
924 switch (ch)
925 {
926 case 'f': // --filename
927 pszFilename = ValueUnion.psz;
928 break;
929
930 default:
931 ch = RTGetOptPrintError(ch, &ValueUnion);
932 printUsage(g_pStdErr);
933 return ch;
934 }
935 }
936
937 /* Check for mandatory parameters. */
938 if (!pszFilename)
939 return errorSyntax("Mandatory --filename option missing\n");
940
941 /* just try it */
942 char *pszFormat = NULL;
943 VDTYPE enmType = VDTYPE_INVALID;
944 rc = VDGetFormat(NULL, NULL, pszFilename, &pszFormat, &enmType);
945 if (RT_FAILURE(rc))
946 return errorSyntax("Format autodetect failed: %Rrc\n", rc);
947
948 rc = VDCreate(pVDIfs, enmType, &pDisk);
949 if (RT_FAILURE(rc))
950 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
951
952 /* Open the image */
953 rc = VDOpen(pDisk, pszFormat, pszFilename, VD_OPEN_FLAGS_INFO, NULL);
954 if (RT_FAILURE(rc))
955 return errorRuntime("Error while opening the image: %Rrc\n", rc);
956
957 VDDumpImages(pDisk);
958
959 VDDestroy(pDisk);
960
961 return rc;
962}
963
964
965int handleCompact(HandlerArg *a)
966{
967 int rc = VINF_SUCCESS;
968 PVBOXHDD pDisk = NULL;
969 const char *pszFilename = NULL;
970
971 /* Parse the command line. */
972 static const RTGETOPTDEF s_aOptions[] =
973 {
974 { "--filename", 'f', RTGETOPT_REQ_STRING }
975 };
976 int ch;
977 RTGETOPTUNION ValueUnion;
978 RTGETOPTSTATE GetState;
979 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
980 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
981 {
982 switch (ch)
983 {
984 case 'f': // --filename
985 pszFilename = ValueUnion.psz;
986 break;
987
988 default:
989 ch = RTGetOptPrintError(ch, &ValueUnion);
990 printUsage(g_pStdErr);
991 return ch;
992 }
993 }
994
995 /* Check for mandatory parameters. */
996 if (!pszFilename)
997 return errorSyntax("Mandatory --filename option missing\n");
998
999 /* just try it */
1000 char *pszFormat = NULL;
1001 VDTYPE enmType = VDTYPE_INVALID;
1002 rc = VDGetFormat(NULL, NULL, pszFilename, &pszFormat, &enmType);
1003 if (RT_FAILURE(rc))
1004 return errorSyntax("Format autodetect failed: %Rrc\n", rc);
1005
1006 rc = VDCreate(pVDIfs, enmType, &pDisk);
1007 if (RT_FAILURE(rc))
1008 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
1009
1010 /* Open the image */
1011 rc = VDOpen(pDisk, pszFormat, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
1012 if (RT_FAILURE(rc))
1013 return errorRuntime("Error while opening the image: %Rrc\n", rc);
1014
1015 rc = VDCompact(pDisk, 0, NULL);
1016 if (RT_FAILURE(rc))
1017 errorRuntime("Error while compacting image: %Rrc\n", rc);
1018
1019 VDDestroy(pDisk);
1020
1021 return rc;
1022}
1023
1024
1025int handleCreateCache(HandlerArg *a)
1026{
1027 int rc = VINF_SUCCESS;
1028 PVBOXHDD pDisk = NULL;
1029 const char *pszFilename = NULL;
1030 uint64_t cbSize = 0;
1031
1032 /* Parse the command line. */
1033 static const RTGETOPTDEF s_aOptions[] =
1034 {
1035 { "--filename", 'f', RTGETOPT_REQ_STRING },
1036 { "--size", 's', RTGETOPT_REQ_UINT64 }
1037 };
1038 int ch;
1039 RTGETOPTUNION ValueUnion;
1040 RTGETOPTSTATE GetState;
1041 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
1042 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1043 {
1044 switch (ch)
1045 {
1046 case 'f': // --filename
1047 pszFilename = ValueUnion.psz;
1048 break;
1049
1050 case 's': // --size
1051 cbSize = ValueUnion.u64;
1052 break;
1053
1054 default:
1055 ch = RTGetOptPrintError(ch, &ValueUnion);
1056 printUsage(g_pStdErr);
1057 return ch;
1058 }
1059 }
1060
1061 /* Check for mandatory parameters. */
1062 if (!pszFilename)
1063 return errorSyntax("Mandatory --filename option missing\n");
1064
1065 if (!cbSize)
1066 return errorSyntax("Mandatory --size option missing\n");
1067
1068 /* just try it */
1069 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1070 if (RT_FAILURE(rc))
1071 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
1072
1073 rc = VDCreateCache(pDisk, "VCI", pszFilename, cbSize, VD_IMAGE_FLAGS_DEFAULT,
1074 NULL, NULL, VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1075 if (RT_FAILURE(rc))
1076 return errorRuntime("Error while creating the virtual disk cache: %Rrc\n", rc);
1077
1078 VDDestroy(pDisk);
1079
1080 return rc;
1081}
1082
1083
1084int handleCreateBase(HandlerArg *a)
1085{
1086 int rc = VINF_SUCCESS;
1087 PVBOXHDD pDisk = NULL;
1088 const char *pszFilename = NULL;
1089 const char *pszBackend = "VDI";
1090 const char *pszVariant = NULL;
1091 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
1092 uint64_t cbSize = 0;
1093 VDGEOMETRY LCHSGeometry, PCHSGeometry;
1094
1095 memset(&LCHSGeometry, 0, sizeof(VDGEOMETRY));
1096 memset(&PCHSGeometry, 0, sizeof(VDGEOMETRY));
1097
1098 /* Parse the command line. */
1099 static const RTGETOPTDEF s_aOptions[] =
1100 {
1101 { "--filename", 'f', RTGETOPT_REQ_STRING },
1102 { "--size", 's', RTGETOPT_REQ_UINT64 },
1103 { "--format", 'b', RTGETOPT_REQ_STRING },
1104 { "--variant", 'v', RTGETOPT_REQ_STRING }
1105 };
1106 int ch;
1107 RTGETOPTUNION ValueUnion;
1108 RTGETOPTSTATE GetState;
1109 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
1110 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1111 {
1112 switch (ch)
1113 {
1114 case 'f': // --filename
1115 pszFilename = ValueUnion.psz;
1116 break;
1117
1118 case 's': // --size
1119 cbSize = ValueUnion.u64;
1120 break;
1121
1122 case 'b': // --format
1123 pszBackend = ValueUnion.psz;
1124 break;
1125
1126 case 'v': // --variant
1127 pszVariant = ValueUnion.psz;
1128 break;
1129
1130 default:
1131 ch = RTGetOptPrintError(ch, &ValueUnion);
1132 printUsage(g_pStdErr);
1133 return ch;
1134 }
1135 }
1136
1137 /* Check for mandatory parameters. */
1138 if (!pszFilename)
1139 return errorSyntax("Mandatory --filename option missing\n");
1140
1141 if (!cbSize)
1142 return errorSyntax("Mandatory --size option missing\n");
1143
1144 if (pszVariant)
1145 {
1146 rc = parseDiskVariant(pszVariant, &uImageFlags);
1147 if (RT_FAILURE(rc))
1148 return errorSyntax("Invalid variant %s given\n", pszVariant);
1149 }
1150
1151 /* just try it */
1152 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1153 if (RT_FAILURE(rc))
1154 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
1155
1156 rc = VDCreateBase(pDisk, pszBackend, pszFilename, cbSize, uImageFlags,
1157 NULL, &PCHSGeometry, &LCHSGeometry, NULL, VD_OPEN_FLAGS_NORMAL,
1158 NULL, NULL);
1159 if (RT_FAILURE(rc))
1160 return errorRuntime("Error while creating the virtual disk: %Rrc\n", rc);
1161
1162 VDDestroy(pDisk);
1163
1164 return rc;
1165}
1166
1167
1168int handleRepair(HandlerArg *a)
1169{
1170 int rc = VINF_SUCCESS;
1171 PVBOXHDD pDisk = NULL;
1172 const char *pszFilename = NULL;
1173 char *pszBackend = NULL;
1174 const char *pszFormat = NULL;
1175 bool fDryRun = false;
1176 VDTYPE enmType = VDTYPE_HDD;
1177
1178 /* Parse the command line. */
1179 static const RTGETOPTDEF s_aOptions[] =
1180 {
1181 { "--filename", 'f', RTGETOPT_REQ_STRING },
1182 { "--dry-run", 'd', RTGETOPT_REQ_NOTHING },
1183 { "--format", 'b', RTGETOPT_REQ_STRING }
1184 };
1185 int ch;
1186 RTGETOPTUNION ValueUnion;
1187 RTGETOPTSTATE GetState;
1188 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
1189 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1190 {
1191 switch (ch)
1192 {
1193 case 'f': // --filename
1194 pszFilename = ValueUnion.psz;
1195 break;
1196
1197 case 'd': // --dry-run
1198 fDryRun = true;
1199 break;
1200
1201 case 'b': // --format
1202 pszFormat = ValueUnion.psz;
1203 break;
1204
1205 default:
1206 ch = RTGetOptPrintError(ch, &ValueUnion);
1207 printUsage(g_pStdErr);
1208 return ch;
1209 }
1210 }
1211
1212 /* Check for mandatory parameters. */
1213 if (!pszFilename)
1214 return errorSyntax("Mandatory --filename option missing\n");
1215
1216 /* just try it */
1217 if (!pszFormat)
1218 {
1219 rc = VDGetFormat(NULL, NULL, pszFilename, &pszBackend, &enmType);
1220 if (RT_FAILURE(rc))
1221 return errorSyntax("Format autodetect failed: %Rrc\n", rc);
1222 pszFormat = pszBackend;
1223 }
1224
1225 rc = VDRepair(pVDIfs, NULL, pszFilename, pszFormat, fDryRun ? VD_REPAIR_DRY_RUN : 0);
1226 if (RT_FAILURE(rc))
1227 rc = errorRuntime("Error while repairing the virtual disk: %Rrc\n", rc);
1228
1229 if (pszBackend)
1230 RTStrFree(pszBackend);
1231 return rc;
1232}
1233
1234
1235int main(int argc, char *argv[])
1236{
1237 int exitcode = 0;
1238
1239 int rc = RTR3InitExe(argc, &argv, 0);
1240 if (RT_FAILURE(rc))
1241 return RTMsgInitFailure(rc);
1242
1243 g_pszProgName = RTPathFilename(argv[0]);
1244
1245 bool fShowLogo = false;
1246 int iCmd = 1;
1247 int iCmdArg;
1248
1249 /* global options */
1250 for (int i = 1; i < argc || argc <= iCmd; i++)
1251 {
1252 if ( argc <= iCmd
1253 || !strcmp(argv[i], "help")
1254 || !strcmp(argv[i], "-?")
1255 || !strcmp(argv[i], "-h")
1256 || !strcmp(argv[i], "-help")
1257 || !strcmp(argv[i], "--help"))
1258 {
1259 showLogo(g_pStdOut);
1260 printUsage(g_pStdOut);
1261 return 0;
1262 }
1263
1264 if ( !strcmp(argv[i], "-v")
1265 || !strcmp(argv[i], "-version")
1266 || !strcmp(argv[i], "-Version")
1267 || !strcmp(argv[i], "--version"))
1268 {
1269 /* Print version number, and do nothing else. */
1270 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
1271 return 0;
1272 }
1273
1274 if ( !strcmp(argv[i], "--nologo")
1275 || !strcmp(argv[i], "-nologo")
1276 || !strcmp(argv[i], "-q"))
1277 {
1278 /* suppress the logo */
1279 fShowLogo = false;
1280 iCmd++;
1281 }
1282 else
1283 {
1284 break;
1285 }
1286 }
1287
1288 iCmdArg = iCmd + 1;
1289
1290 if (fShowLogo)
1291 showLogo(g_pStdOut);
1292
1293 /* initialize the VD backend with dummy handlers */
1294 VDINTERFACEERROR vdInterfaceError;
1295 vdInterfaceError.pfnError = handleVDError;
1296 vdInterfaceError.pfnMessage = handleVDMessage;
1297
1298 rc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1299 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
1300
1301 rc = VDInit();
1302 if (RT_FAILURE(rc))
1303 {
1304 errorSyntax("Initializing backends failed! rc=%Rrc\n", rc);
1305 return 1;
1306 }
1307
1308 /*
1309 * All registered command handlers
1310 */
1311 static const struct
1312 {
1313 const char *command;
1314 int (*handler)(HandlerArg *a);
1315 } s_commandHandlers[] =
1316 {
1317 { "setuuid", handleSetUUID },
1318 { "convert", handleConvert },
1319 { "info", handleInfo },
1320 { "compact", handleCompact },
1321 { "createcache", handleCreateCache },
1322 { "createbase", handleCreateBase },
1323 { "repair", handleRepair },
1324 { NULL, NULL }
1325 };
1326
1327 HandlerArg handlerArg = { 0, NULL };
1328 int commandIndex;
1329 for (commandIndex = 0; s_commandHandlers[commandIndex].command != NULL; commandIndex++)
1330 {
1331 if (!strcmp(s_commandHandlers[commandIndex].command, argv[iCmd]))
1332 {
1333 handlerArg.argc = argc - iCmdArg;
1334 handlerArg.argv = &argv[iCmdArg];
1335
1336 exitcode = s_commandHandlers[commandIndex].handler(&handlerArg);
1337 break;
1338 }
1339 }
1340 if (!s_commandHandlers[commandIndex].command)
1341 {
1342 errorSyntax("Invalid command '%s'", argv[iCmd]);
1343 return 1;
1344 }
1345
1346 rc = VDShutdown();
1347 if (RT_FAILURE(rc))
1348 {
1349 errorSyntax("Unloading backends failed! rc=%Rrc\n", rc);
1350 return 1;
1351 }
1352
1353 return exitcode;
1354}
1355
1356/* dummy stub for RuntimeR3 */
1357#ifndef RT_OS_WINDOWS
1358RTDECL(bool) RTAssertShouldPanic(void)
1359{
1360 return true;
1361}
1362#endif
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