VirtualBox

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

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

Storage: Implement repair callback for VDI, fixes for the VHD repair callback and add repair command to vbox-img

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.7 KB
Line 
1/* $Id: vbox-img.cpp 40240 2012-02-23 20:51:34Z 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 }
445
446 /* Read several blocks and assemble the result if necessary */
447 size_t cbTotalRead = 0;
448 do
449 {
450 /* Skip over areas no one wants to read. */
451 while (uOffset > pFS->offBuffer + pFS->cbBuffer - 1)
452 {
453 if (pFS->cbBuffer < sizeof(pFS->abBuffer))
454 {
455 if (pcbRead)
456 *pcbRead = cbTotalRead;
457 return VERR_EOF;
458 }
459
460 /* Repeat reading until buffer is full or EOF. */
461 size_t cbSumRead = 0, cbRead;
462 uint8_t *pTmp = (uint8_t *)&pFS->abBuffer[0];
463 size_t cbTmp = sizeof(pFS->abBuffer);
464 do
465 {
466 rc = RTFileRead(pFS->file, pTmp, cbTmp, &cbRead);
467 if (RT_FAILURE(rc))
468 return rc;
469 pTmp += cbRead;
470 cbTmp -= cbRead;
471 cbSumRead += cbRead;
472 } while (cbTmp && cbRead);
473
474 pFS->offBuffer += pFS->cbBuffer;
475 pFS->cbBuffer = cbSumRead;
476 }
477
478 uint32_t cbThisRead = RT_MIN(cbBuffer,
479 pFS->cbBuffer - uOffset % sizeof(pFS->abBuffer));
480 memcpy(pvBuffer, &pFS->abBuffer[uOffset % sizeof(pFS->abBuffer)],
481 cbThisRead);
482 uOffset += cbThisRead;
483 pvBuffer = (uint8_t *)pvBuffer + cbThisRead;
484 cbBuffer -= cbThisRead;
485 cbTotalRead += cbThisRead;
486 } while (cbBuffer > 0);
487
488 if (pcbRead)
489 *pcbRead = cbTotalRead;
490
491 pFS->off = uOffset;
492
493 return VINF_SUCCESS;
494}
495
496static int convInWrite(void *pvUser, void *pStorage, uint64_t uOffset,
497 const void *pvBuffer, size_t cbBuffer,
498 size_t *pcbWritten)
499{
500 NOREF(pvUser);
501 NOREF(pStorage);
502 NOREF(uOffset);
503 NOREF(cbBuffer);
504 NOREF(pcbWritten);
505 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
506 AssertFailedReturn(VERR_NOT_SUPPORTED);
507}
508
509static int convInFlush(void *pvUser, void *pStorage)
510{
511 NOREF(pvUser);
512 NOREF(pStorage);
513 return VINF_SUCCESS;
514}
515
516static int convOutOpen(void *pvUser, const char *pszLocation,
517 uint32_t fOpen, PFNVDCOMPLETED pfnCompleted,
518 void **ppStorage)
519{
520 NOREF(pvUser);
521 /* Validate input. */
522 AssertPtrReturn(ppStorage, VERR_INVALID_POINTER);
523 AssertPtrNullReturn(pfnCompleted, VERR_INVALID_PARAMETER);
524 AssertReturn((fOpen & RTFILE_O_ACCESS_MASK) == RTFILE_O_WRITE, VERR_INVALID_PARAMETER);
525 RTFILE file;
526 int rc = RTFileFromNative(&file, RTFILE_NATIVE_STDOUT);
527 if (RT_FAILURE(rc))
528 return rc;
529
530 /* Must clear buffer, so that skipped over data is initialized properly. */
531 PFILEIOSTATE pFS = (PFILEIOSTATE)RTMemAllocZ(sizeof(FILEIOSTATE));
532 if (!pFS)
533 return VERR_NO_MEMORY;
534
535 pFS->file = file;
536 pFS->off = 0;
537 pFS->offBuffer = 0;
538 pFS->cbBuffer = sizeof(FILEIOSTATE);
539
540 *ppStorage = pFS;
541 return VINF_SUCCESS;
542}
543
544static int convOutClose(void *pvUser, void *pStorage)
545{
546 NOREF(pvUser);
547 AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
548 PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
549 int rc = VINF_SUCCESS;
550
551 /* Flush any remaining buffer contents. */
552 if (pFS->cbBuffer)
553 rc = RTFileWrite(pFS->file, &pFS->abBuffer[0], pFS->cbBuffer, NULL);
554
555 RTMemFree(pFS);
556
557 return rc;
558}
559
560static int convOutDelete(void *pvUser, const char *pcszFilename)
561{
562 NOREF(pvUser);
563 NOREF(pcszFilename);
564 AssertFailedReturn(VERR_NOT_SUPPORTED);
565}
566
567static int convOutMove(void *pvUser, const char *pcszSrc, const char *pcszDst,
568 unsigned fMove)
569{
570 NOREF(pvUser);
571 NOREF(pcszSrc);
572 NOREF(pcszDst);
573 NOREF(fMove);
574 AssertFailedReturn(VERR_NOT_SUPPORTED);
575}
576
577static int convOutGetFreeSpace(void *pvUser, const char *pcszFilename,
578 int64_t *pcbFreeSpace)
579{
580 NOREF(pvUser);
581 NOREF(pcszFilename);
582 AssertPtrReturn(pcbFreeSpace, VERR_INVALID_POINTER);
583 *pcbFreeSpace = INT64_MAX;
584 return VINF_SUCCESS;
585}
586
587static int convOutGetModificationTime(void *pvUser, const char *pcszFilename,
588 PRTTIMESPEC pModificationTime)
589{
590 NOREF(pvUser);
591 NOREF(pcszFilename);
592 AssertPtrReturn(pModificationTime, VERR_INVALID_POINTER);
593 AssertFailedReturn(VERR_NOT_SUPPORTED);
594}
595
596static int convOutGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
597{
598 NOREF(pvUser);
599 NOREF(pStorage);
600 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
601 AssertFailedReturn(VERR_NOT_SUPPORTED);
602}
603
604static int convOutSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
605{
606 NOREF(pvUser);
607 NOREF(pStorage);
608 NOREF(cbSize);
609 AssertFailedReturn(VERR_NOT_SUPPORTED);
610}
611
612static int convOutRead(void *pvUser, void *pStorage, uint64_t uOffset,
613 void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
614{
615 NOREF(pvUser);
616 NOREF(pStorage);
617 NOREF(uOffset);
618 NOREF(cbBuffer);
619 NOREF(pcbRead);
620 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
621 AssertFailedReturn(VERR_NOT_SUPPORTED);
622}
623
624static int convOutWrite(void *pvUser, void *pStorage, uint64_t uOffset,
625 const void *pvBuffer, size_t cbBuffer,
626 size_t *pcbWritten)
627{
628 NOREF(pvUser);
629 AssertPtrReturn(pStorage, VERR_INVALID_POINTER);
630 AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
631 PFILEIOSTATE pFS = (PFILEIOSTATE)pStorage;
632 AssertReturn(uOffset >= pFS->off, VERR_INVALID_PARAMETER);
633 int rc;
634
635 /* Write the data to the buffer, flushing as required. */
636 size_t cbTotalWritten = 0;
637 do
638 {
639 /* Flush the buffer if we need a new one. */
640 while (uOffset > pFS->offBuffer + sizeof(pFS->abBuffer) - 1)
641 {
642 rc = RTFileWrite(pFS->file, &pFS->abBuffer[0],
643 sizeof(pFS->abBuffer), NULL);
644 RT_ZERO(pFS->abBuffer);
645 pFS->offBuffer += sizeof(pFS->abBuffer);
646 pFS->cbBuffer = 0;
647 }
648
649 uint32_t cbThisWrite = RT_MIN(cbBuffer,
650 sizeof(pFS->abBuffer) - uOffset % sizeof(pFS->abBuffer));
651 memcpy(&pFS->abBuffer[uOffset % sizeof(pFS->abBuffer)], pvBuffer,
652 cbThisWrite);
653 uOffset += cbThisWrite;
654 pvBuffer = (uint8_t *)pvBuffer + cbThisWrite;
655 cbBuffer -= cbThisWrite;
656 cbTotalWritten += cbThisWrite;
657 } while (cbBuffer > 0);
658
659 if (pcbWritten)
660 *pcbWritten = cbTotalWritten;
661
662 pFS->cbBuffer = uOffset % sizeof(pFS->abBuffer);
663 if (!pFS->cbBuffer)
664 pFS->cbBuffer = sizeof(pFS->abBuffer);
665 pFS->off = uOffset;
666
667 return VINF_SUCCESS;
668}
669
670static int convOutFlush(void *pvUser, void *pStorage)
671{
672 NOREF(pvUser);
673 NOREF(pStorage);
674 return VINF_SUCCESS;
675}
676
677int handleConvert(HandlerArg *a)
678{
679 const char *pszSrcFilename = NULL;
680 const char *pszDstFilename = NULL;
681 bool fStdIn = false;
682 bool fStdOut = false;
683 const char *pszSrcFormat = NULL;
684 VDTYPE enmSrcType = VDTYPE_HDD;
685 const char *pszDstFormat = NULL;
686 const char *pszVariant = NULL;
687 PVBOXHDD pSrcDisk = NULL;
688 PVBOXHDD pDstDisk = NULL;
689 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
690 PVDINTERFACE pIfsImageInput = NULL;
691 PVDINTERFACE pIfsImageOutput = NULL;
692 VDINTERFACEIO IfsInputIO;
693 VDINTERFACEIO IfsOutputIO;
694 int rc = VINF_SUCCESS;
695
696 /* Parse the command line. */
697 static const RTGETOPTDEF s_aOptions[] =
698 {
699 { "--srcfilename", 'i', RTGETOPT_REQ_STRING },
700 { "--dstfilename", 'o', RTGETOPT_REQ_STRING },
701 { "--stdin", 'p', RTGETOPT_REQ_NOTHING },
702 { "--stdout", 'P', RTGETOPT_REQ_NOTHING },
703 { "--srcformat", 's', RTGETOPT_REQ_STRING },
704 { "--dstformat", 'd', RTGETOPT_REQ_STRING },
705 { "--variant", 'v', RTGETOPT_REQ_STRING }
706 };
707 int ch;
708 RTGETOPTUNION ValueUnion;
709 RTGETOPTSTATE GetState;
710 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
711 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
712 {
713 switch (ch)
714 {
715 case 'i': // --srcfilename
716 pszSrcFilename = ValueUnion.psz;
717 break;
718 case 'o': // --dstfilename
719 pszDstFilename = ValueUnion.psz;
720 break;
721 case 'p': // --stdin
722 fStdIn = true;
723 break;
724 case 'P': // --stdout
725 fStdOut = true;
726 break;
727 case 's': // --srcformat
728 pszSrcFormat = ValueUnion.psz;
729 break;
730 case 'd': // --dstformat
731 pszDstFormat = ValueUnion.psz;
732 break;
733 case 'v': // --variant
734 pszVariant = ValueUnion.psz;
735 break;
736
737 default:
738 ch = RTGetOptPrintError(ch, &ValueUnion);
739 printUsage(g_pStdErr);
740 return ch;
741 }
742 }
743
744 /* Check for mandatory parameters and handle dummies/defaults. */
745 if (fStdIn && !pszSrcFormat)
746 return errorSyntax("Mandatory --srcformat option missing\n");
747 if (!pszDstFormat)
748 pszDstFormat = "VDI";
749 if (fStdIn && !pszSrcFilename)
750 {
751 /* Complete dummy, will be just passed to various calls to fulfill
752 * the "must be non-NULL" requirement, and is completely ignored
753 * otherwise. It shown in the stderr message below. */
754 pszSrcFilename = "stdin";
755 }
756 if (fStdOut && !pszDstFilename)
757 {
758 /* Will be stored in the destination image if it is a streamOptimized
759 * VMDK, but it isn't really relevant - use it for "branding". */
760 if (!RTStrICmp(pszDstFormat, "VMDK"))
761 pszDstFilename = "VirtualBoxStream.vmdk";
762 else
763 pszDstFilename = "stdout";
764 }
765 if (!pszSrcFilename)
766 return errorSyntax("Mandatory --srcfilename option missing\n");
767 if (!pszDstFilename)
768 return errorSyntax("Mandatory --dstfilename option missing\n");
769
770 if (fStdIn)
771 {
772 IfsInputIO.pfnOpen = convInOpen;
773 IfsInputIO.pfnClose = convInClose;
774 IfsInputIO.pfnDelete = convInDelete;
775 IfsInputIO.pfnMove = convInMove;
776 IfsInputIO.pfnGetFreeSpace = convInGetFreeSpace;
777 IfsInputIO.pfnGetModificationTime = convInGetModificationTime;
778 IfsInputIO.pfnGetSize = convInGetSize;
779 IfsInputIO.pfnSetSize = convInSetSize;
780 IfsInputIO.pfnReadSync = convInRead;
781 IfsInputIO.pfnWriteSync = convInWrite;
782 IfsInputIO.pfnFlushSync = convInFlush;
783 VDInterfaceAdd(&IfsInputIO.Core, "stdin", VDINTERFACETYPE_IO,
784 NULL, sizeof(VDINTERFACEIO), &pIfsImageInput);
785 }
786 if (fStdOut)
787 {
788 IfsOutputIO.pfnOpen = convOutOpen;
789 IfsOutputIO.pfnClose = convOutClose;
790 IfsOutputIO.pfnDelete = convOutDelete;
791 IfsOutputIO.pfnMove = convOutMove;
792 IfsOutputIO.pfnGetFreeSpace = convOutGetFreeSpace;
793 IfsOutputIO.pfnGetModificationTime = convOutGetModificationTime;
794 IfsOutputIO.pfnGetSize = convOutGetSize;
795 IfsOutputIO.pfnSetSize = convOutSetSize;
796 IfsOutputIO.pfnReadSync = convOutRead;
797 IfsOutputIO.pfnWriteSync = convOutWrite;
798 IfsOutputIO.pfnFlushSync = convOutFlush;
799 VDInterfaceAdd(&IfsOutputIO.Core, "stdout", VDINTERFACETYPE_IO,
800 NULL, sizeof(VDINTERFACEIO), &pIfsImageOutput);
801 }
802
803 /* check the variant parameter */
804 if (pszVariant)
805 {
806 char *psz = (char*)pszVariant;
807 while (psz && *psz && RT_SUCCESS(rc))
808 {
809 size_t len;
810 const char *pszComma = strchr(psz, ',');
811 if (pszComma)
812 len = pszComma - psz;
813 else
814 len = strlen(psz);
815 if (len > 0)
816 {
817 if (!RTStrNICmp(pszVariant, "standard", len))
818 uImageFlags |= VD_IMAGE_FLAGS_NONE;
819 else if (!RTStrNICmp(pszVariant, "fixed", len))
820 uImageFlags |= VD_IMAGE_FLAGS_FIXED;
821 else if (!RTStrNICmp(pszVariant, "split2g", len))
822 uImageFlags |= VD_VMDK_IMAGE_FLAGS_SPLIT_2G;
823 else if (!RTStrNICmp(pszVariant, "stream", len))
824 uImageFlags |= VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED;
825 else if (!RTStrNICmp(pszVariant, "esx", len))
826 uImageFlags |= VD_VMDK_IMAGE_FLAGS_ESX;
827 else
828 return errorSyntax("Invalid --variant option\n");
829 }
830 if (pszComma)
831 psz += len + 1;
832 else
833 psz += len;
834 }
835 }
836
837 do
838 {
839 /* try to determine input format if not specified */
840 if (!pszSrcFormat)
841 {
842 char *pszFormat = NULL;
843 VDTYPE enmType = VDTYPE_INVALID;
844 rc = VDGetFormat(NULL, NULL, pszSrcFilename, &pszFormat, &enmType);
845 if (RT_FAILURE(rc))
846 {
847 errorSyntax("No file format specified, please specify format: %Rrc\n", rc);
848 break;
849 }
850 pszSrcFormat = pszFormat;
851 enmSrcType = enmType;
852 }
853
854 rc = VDCreate(pVDIfs, enmSrcType, &pSrcDisk);
855 if (RT_FAILURE(rc))
856 {
857 errorRuntime("Error while creating source disk container: %Rrc\n", rc);
858 break;
859 }
860
861 rc = VDOpen(pSrcDisk, pszSrcFormat, pszSrcFilename,
862 VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_SEQUENTIAL,
863 pIfsImageInput);
864 if (RT_FAILURE(rc))
865 {
866 errorRuntime("Error while opening source image: %Rrc\n", rc);
867 break;
868 }
869
870 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDstDisk);
871 if (RT_FAILURE(rc))
872 {
873 errorRuntime("Error while creating the destination disk container: %Rrc\n", rc);
874 break;
875 }
876
877 uint64_t cbSize = VDGetSize(pSrcDisk, VD_LAST_IMAGE);
878 RTStrmPrintf(g_pStdErr, "Converting image \"%s\" with size %RU64 bytes (%RU64MB)...\n", pszSrcFilename, cbSize, (cbSize + _1M - 1) / _1M);
879
880 /* Create the output image */
881 rc = VDCopy(pSrcDisk, VD_LAST_IMAGE, pDstDisk, pszDstFormat,
882 pszDstFilename, false, 0, uImageFlags, NULL,
883 VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_SEQUENTIAL, NULL,
884 pIfsImageOutput, NULL);
885 if (RT_FAILURE(rc))
886 {
887 errorRuntime("Error while copying the image: %Rrc\n", rc);
888 break;
889 }
890
891 }
892 while (0);
893
894 if (pDstDisk)
895 VDDestroy(pDstDisk);
896 if (pSrcDisk)
897 VDDestroy(pSrcDisk);
898
899 return RT_SUCCESS(rc) ? 0 : 1;
900}
901
902
903int handleInfo(HandlerArg *a)
904{
905 int rc = VINF_SUCCESS;
906 PVBOXHDD pDisk = NULL;
907 const char *pszFilename = NULL;
908
909 /* Parse the command line. */
910 static const RTGETOPTDEF s_aOptions[] =
911 {
912 { "--filename", 'f', RTGETOPT_REQ_STRING }
913 };
914 int ch;
915 RTGETOPTUNION ValueUnion;
916 RTGETOPTSTATE GetState;
917 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
918 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
919 {
920 switch (ch)
921 {
922 case 'f': // --filename
923 pszFilename = ValueUnion.psz;
924 break;
925
926 default:
927 ch = RTGetOptPrintError(ch, &ValueUnion);
928 printUsage(g_pStdErr);
929 return ch;
930 }
931 }
932
933 /* Check for mandatory parameters. */
934 if (!pszFilename)
935 return errorSyntax("Mandatory --filename option missing\n");
936
937 /* just try it */
938 char *pszFormat = NULL;
939 VDTYPE enmType = VDTYPE_INVALID;
940 rc = VDGetFormat(NULL, NULL, pszFilename, &pszFormat, &enmType);
941 if (RT_FAILURE(rc))
942 return errorSyntax("Format autodetect failed: %Rrc\n", rc);
943
944 rc = VDCreate(pVDIfs, enmType, &pDisk);
945 if (RT_FAILURE(rc))
946 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
947
948 /* Open the image */
949 rc = VDOpen(pDisk, pszFormat, pszFilename, VD_OPEN_FLAGS_INFO, NULL);
950 if (RT_FAILURE(rc))
951 return errorRuntime("Error while opening the image: %Rrc\n", rc);
952
953 VDDumpImages(pDisk);
954
955 VDDestroy(pDisk);
956
957 return rc;
958}
959
960
961int handleCompact(HandlerArg *a)
962{
963 int rc = VINF_SUCCESS;
964 PVBOXHDD pDisk = NULL;
965 const char *pszFilename = NULL;
966
967 /* Parse the command line. */
968 static const RTGETOPTDEF s_aOptions[] =
969 {
970 { "--filename", 'f', RTGETOPT_REQ_STRING }
971 };
972 int ch;
973 RTGETOPTUNION ValueUnion;
974 RTGETOPTSTATE GetState;
975 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
976 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
977 {
978 switch (ch)
979 {
980 case 'f': // --filename
981 pszFilename = ValueUnion.psz;
982 break;
983
984 default:
985 ch = RTGetOptPrintError(ch, &ValueUnion);
986 printUsage(g_pStdErr);
987 return ch;
988 }
989 }
990
991 /* Check for mandatory parameters. */
992 if (!pszFilename)
993 return errorSyntax("Mandatory --filename option missing\n");
994
995 /* just try it */
996 char *pszFormat = NULL;
997 VDTYPE enmType = VDTYPE_INVALID;
998 rc = VDGetFormat(NULL, NULL, pszFilename, &pszFormat, &enmType);
999 if (RT_FAILURE(rc))
1000 return errorSyntax("Format autodetect failed: %Rrc\n", rc);
1001
1002 rc = VDCreate(pVDIfs, enmType, &pDisk);
1003 if (RT_FAILURE(rc))
1004 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
1005
1006 /* Open the image */
1007 rc = VDOpen(pDisk, pszFormat, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
1008 if (RT_FAILURE(rc))
1009 return errorRuntime("Error while opening the image: %Rrc\n", rc);
1010
1011 rc = VDCompact(pDisk, 0, NULL);
1012 if (RT_FAILURE(rc))
1013 errorRuntime("Error while compacting image: %Rrc\n", rc);
1014
1015 VDDestroy(pDisk);
1016
1017 return rc;
1018}
1019
1020
1021int handleCreateCache(HandlerArg *a)
1022{
1023 int rc = VINF_SUCCESS;
1024 PVBOXHDD pDisk = NULL;
1025 const char *pszFilename = NULL;
1026 uint64_t cbSize = 0;
1027
1028 /* Parse the command line. */
1029 static const RTGETOPTDEF s_aOptions[] =
1030 {
1031 { "--filename", 'f', RTGETOPT_REQ_STRING },
1032 { "--size", 's', RTGETOPT_REQ_UINT64 }
1033 };
1034 int ch;
1035 RTGETOPTUNION ValueUnion;
1036 RTGETOPTSTATE GetState;
1037 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
1038 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1039 {
1040 switch (ch)
1041 {
1042 case 'f': // --filename
1043 pszFilename = ValueUnion.psz;
1044 break;
1045
1046 case 's': // --size
1047 cbSize = ValueUnion.u64;
1048 break;
1049
1050 default:
1051 ch = RTGetOptPrintError(ch, &ValueUnion);
1052 printUsage(g_pStdErr);
1053 return ch;
1054 }
1055 }
1056
1057 /* Check for mandatory parameters. */
1058 if (!pszFilename)
1059 return errorSyntax("Mandatory --filename option missing\n");
1060
1061 if (!cbSize)
1062 return errorSyntax("Mandatory --size option missing\n");
1063
1064 /* just try it */
1065 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1066 if (RT_FAILURE(rc))
1067 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
1068
1069 rc = VDCreateCache(pDisk, "VCI", pszFilename, cbSize, VD_IMAGE_FLAGS_DEFAULT,
1070 NULL, NULL, VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1071 if (RT_FAILURE(rc))
1072 return errorRuntime("Error while creating the virtual disk cache: %Rrc\n", rc);
1073
1074 VDDestroy(pDisk);
1075
1076 return rc;
1077}
1078
1079
1080int handleCreateBase(HandlerArg *a)
1081{
1082 int rc = VINF_SUCCESS;
1083 PVBOXHDD pDisk = NULL;
1084 const char *pszFilename = NULL;
1085 const char *pszBackend = "VDI";
1086 const char *pszVariant = NULL;
1087 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
1088 uint64_t cbSize = 0;
1089 VDGEOMETRY LCHSGeometry, PCHSGeometry;
1090
1091 memset(&LCHSGeometry, 0, sizeof(VDGEOMETRY));
1092 memset(&PCHSGeometry, 0, sizeof(VDGEOMETRY));
1093
1094 /* Parse the command line. */
1095 static const RTGETOPTDEF s_aOptions[] =
1096 {
1097 { "--filename", 'f', RTGETOPT_REQ_STRING },
1098 { "--size", 's', RTGETOPT_REQ_UINT64 },
1099 { "--format", 'b', RTGETOPT_REQ_STRING },
1100 { "--variant", 'v', RTGETOPT_REQ_STRING }
1101 };
1102 int ch;
1103 RTGETOPTUNION ValueUnion;
1104 RTGETOPTSTATE GetState;
1105 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
1106 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1107 {
1108 switch (ch)
1109 {
1110 case 'f': // --filename
1111 pszFilename = ValueUnion.psz;
1112 break;
1113
1114 case 's': // --size
1115 cbSize = ValueUnion.u64;
1116 break;
1117
1118 case 'b': // --format
1119 pszBackend = ValueUnion.psz;
1120 break;
1121
1122 case 'v': // --variant
1123 pszVariant = ValueUnion.psz;
1124 break;
1125
1126 default:
1127 ch = RTGetOptPrintError(ch, &ValueUnion);
1128 printUsage(g_pStdErr);
1129 return ch;
1130 }
1131 }
1132
1133 /* Check for mandatory parameters. */
1134 if (!pszFilename)
1135 return errorSyntax("Mandatory --filename option missing\n");
1136
1137 if (!cbSize)
1138 return errorSyntax("Mandatory --size option missing\n");
1139
1140 if (pszVariant)
1141 {
1142 rc = parseDiskVariant(pszVariant, &uImageFlags);
1143 if (RT_FAILURE(rc))
1144 return errorSyntax("Invalid variant %s given\n", pszVariant);
1145 }
1146
1147 /* just try it */
1148 rc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
1149 if (RT_FAILURE(rc))
1150 return errorRuntime("Error while creating the virtual disk container: %Rrc\n", rc);
1151
1152 rc = VDCreateBase(pDisk, pszBackend, pszFilename, cbSize, uImageFlags,
1153 NULL, &PCHSGeometry, &LCHSGeometry, NULL, VD_OPEN_FLAGS_NORMAL,
1154 NULL, NULL);
1155 if (RT_FAILURE(rc))
1156 return errorRuntime("Error while creating the virtual disk: %Rrc\n", rc);
1157
1158 VDDestroy(pDisk);
1159
1160 return rc;
1161}
1162
1163
1164int handleRepair(HandlerArg *a)
1165{
1166 int rc = VINF_SUCCESS;
1167 PVBOXHDD pDisk = NULL;
1168 const char *pszFilename = NULL;
1169 char *pszBackend = NULL;
1170 const char *pszFormat = NULL;
1171 bool fDryRun = false;
1172 VDTYPE enmType = VDTYPE_HDD;
1173
1174 /* Parse the command line. */
1175 static const RTGETOPTDEF s_aOptions[] =
1176 {
1177 { "--filename", 'f', RTGETOPT_REQ_STRING },
1178 { "--dry-run", 'd', RTGETOPT_REQ_NOTHING },
1179 { "--format", 'b', RTGETOPT_REQ_STRING }
1180 };
1181 int ch;
1182 RTGETOPTUNION ValueUnion;
1183 RTGETOPTSTATE GetState;
1184 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0 /* fFlags */);
1185 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1186 {
1187 switch (ch)
1188 {
1189 case 'f': // --filename
1190 pszFilename = ValueUnion.psz;
1191 break;
1192
1193 case 'd': // --dry-run
1194 fDryRun = true;
1195 break;
1196
1197 case 'b': // --format
1198 pszFormat = ValueUnion.psz;
1199 break;
1200
1201 default:
1202 ch = RTGetOptPrintError(ch, &ValueUnion);
1203 printUsage(g_pStdErr);
1204 return ch;
1205 }
1206 }
1207
1208 /* Check for mandatory parameters. */
1209 if (!pszFilename)
1210 return errorSyntax("Mandatory --filename option missing\n");
1211
1212 /* just try it */
1213 if (!pszFormat)
1214 {
1215 rc = VDGetFormat(NULL, NULL, pszFilename, &pszBackend, &enmType);
1216 if (RT_FAILURE(rc))
1217 return errorSyntax("Format autodetect failed: %Rrc\n", rc);
1218 pszFormat = pszBackend;
1219 }
1220
1221 rc = VDRepair(pVDIfs, NULL, pszFilename, pszFormat, fDryRun ? VD_REPAIR_DRY_RUN : 0);
1222 if (RT_FAILURE(rc))
1223 rc = errorRuntime("Error while repairing the virtual disk: %Rrc\n", rc);
1224
1225 if (pszBackend)
1226 RTStrFree(pszBackend);
1227 return rc;
1228}
1229
1230
1231int main(int argc, char *argv[])
1232{
1233 int exitcode = 0;
1234
1235 int rc = RTR3InitExe(argc, &argv, 0);
1236 if (RT_FAILURE(rc))
1237 return RTMsgInitFailure(rc);
1238
1239 g_pszProgName = RTPathFilename(argv[0]);
1240
1241 bool fShowLogo = false;
1242 int iCmd = 1;
1243 int iCmdArg;
1244
1245 /* global options */
1246 for (int i = 1; i < argc || argc <= iCmd; i++)
1247 {
1248 if ( argc <= iCmd
1249 || !strcmp(argv[i], "help")
1250 || !strcmp(argv[i], "-?")
1251 || !strcmp(argv[i], "-h")
1252 || !strcmp(argv[i], "-help")
1253 || !strcmp(argv[i], "--help"))
1254 {
1255 showLogo(g_pStdOut);
1256 printUsage(g_pStdOut);
1257 return 0;
1258 }
1259
1260 if ( !strcmp(argv[i], "-v")
1261 || !strcmp(argv[i], "-version")
1262 || !strcmp(argv[i], "-Version")
1263 || !strcmp(argv[i], "--version"))
1264 {
1265 /* Print version number, and do nothing else. */
1266 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
1267 return 0;
1268 }
1269
1270 if ( !strcmp(argv[i], "--nologo")
1271 || !strcmp(argv[i], "-nologo")
1272 || !strcmp(argv[i], "-q"))
1273 {
1274 /* suppress the logo */
1275 fShowLogo = false;
1276 iCmd++;
1277 }
1278 else
1279 {
1280 break;
1281 }
1282 }
1283
1284 iCmdArg = iCmd + 1;
1285
1286 if (fShowLogo)
1287 showLogo(g_pStdOut);
1288
1289 /* initialize the VD backend with dummy handlers */
1290 VDINTERFACEERROR vdInterfaceError;
1291 vdInterfaceError.pfnError = handleVDError;
1292 vdInterfaceError.pfnMessage = handleVDMessage;
1293
1294 rc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1295 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
1296
1297 rc = VDInit();
1298 if (RT_FAILURE(rc))
1299 {
1300 errorSyntax("Initializing backends failed! rc=%Rrc\n", rc);
1301 return 1;
1302 }
1303
1304 /*
1305 * All registered command handlers
1306 */
1307 static const struct
1308 {
1309 const char *command;
1310 int (*handler)(HandlerArg *a);
1311 } s_commandHandlers[] =
1312 {
1313 { "setuuid", handleSetUUID },
1314 { "convert", handleConvert },
1315 { "info", handleInfo },
1316 { "compact", handleCompact },
1317 { "createcache", handleCreateCache },
1318 { "createbase", handleCreateBase },
1319 { "repair", handleRepair },
1320 { NULL, NULL }
1321 };
1322
1323 HandlerArg handlerArg = { 0, NULL };
1324 int commandIndex;
1325 for (commandIndex = 0; s_commandHandlers[commandIndex].command != NULL; commandIndex++)
1326 {
1327 if (!strcmp(s_commandHandlers[commandIndex].command, argv[iCmd]))
1328 {
1329 handlerArg.argc = argc - iCmdArg;
1330 handlerArg.argv = &argv[iCmdArg];
1331
1332 exitcode = s_commandHandlers[commandIndex].handler(&handlerArg);
1333 break;
1334 }
1335 }
1336 if (!s_commandHandlers[commandIndex].command)
1337 {
1338 errorSyntax("Invalid command '%s'", argv[iCmd]);
1339 return 1;
1340 }
1341
1342 rc = VDShutdown();
1343 if (RT_FAILURE(rc))
1344 {
1345 errorSyntax("Unloading backends failed! rc=%Rrc\n", rc);
1346 return 1;
1347 }
1348
1349 return exitcode;
1350}
1351
1352/* dummy stub for RuntimeR3 */
1353#ifndef RT_OS_WINDOWS
1354RTDECL(bool) RTAssertShouldPanic(void)
1355{
1356 return true;
1357}
1358#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