VirtualBox

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

最後變更 在這個檔案從38469是 38469,由 vboxsync 提交於 14 年 前

VD: Interface cleanup. Merge the two involved structures (generic interface descriptor and callback table) into one, remove the duplicated interface wrappers in the backends and move the interface definitions into separate headers separating public and private interfaces.

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

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