VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/testcase/vditool.cpp@ 8015

Last change on this file since 8015 was 6291, checked in by vboxsync, 17 years ago

Big virtual disk changeset containing several modifications

  • remove the always buggy translation setting and replace it with two sets of geometries, physical and logical
  • complete vmdk creation (fixed/dynamic variants, both split in 2G chunks and single file)
  • implemented VBoxHDD-new generic snapshot support, i.e. diff image creation and image merging (completely untested, I'm pretty sure there are bugs)
  • assorted changes which generalize the VBoxHDD-new interfaces (both externally and internally)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
1/** @file
2 *
3 * VBox HDD container maintenance/conversion utility
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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/VBoxHDD.h>
22#include <iprt/alloc.h>
23#include <iprt/file.h>
24#include <iprt/stream.h>
25#include <iprt/string.h>
26#include <iprt/runtime.h>
27#include <VBox/err.h>
28#include <VBox/log.h>
29
30#include <stdlib.h>
31
32
33
34static void ascii2upper(char *psz)
35{
36 for (;*psz; psz++)
37 if (*psz >= 'a' && *psz <= 'z')
38 *psz += 'A' - 'a';
39}
40
41static int UsageExit()
42{
43 RTPrintf("Usage: vditool <Command> [Params]\n" \
44 "Commands and params:\n" \
45 " NEW Filename Mbytes - create new image;\n" \
46 " DD Filename DDFilename - create new image from DD format image;\n" \
47 " CONVERT Filename - convert VDI image from old format;\n" \
48 " DUMP Filename - debug dump;\n" \
49 " RESETGEO Filename - reset geometry information;\n" \
50 " COPY FromImage ToImage - make image copy;\n" \
51 " COPYDD FromImage DDFilename - make a DD copy of the image;\n" \
52 " SHRINK Filename - optimize (reduce) VDI image size.\n");
53 return 1;
54}
55
56static int SyntaxError(const char *pszMsg)
57{
58 RTPrintf("Syntax error: %s\n\n", pszMsg);
59 UsageExit();
60 return 1;
61}
62
63/**
64 * Our internal functions use UTF8
65 */
66static int FilenameToUtf8(char **pszUtf8Filename, const char *pszFilename)
67{
68 int rc = RTStrCurrentCPToUtf8(pszUtf8Filename, pszFilename);
69 if (VBOX_FAILURE(rc))
70 RTPrintf("Error converting filename '%s' to UTF8! (rc=%Rrc)\n",
71 pszFilename, rc);
72 return rc;
73}
74
75/**
76 * Prints a done message indicating success or failure.
77 * @returns rc
78 * @param rc Status code.
79 */
80static int PrintDone(int rc)
81{
82 if (rc == VINF_SUCCESS)
83 RTPrintf("The operation completed successfully!\n");
84 else if (VBOX_SUCCESS(rc))
85 RTPrintf("The operation completed successfully! (rc=%Rrc)\n", rc);
86 else
87 RTPrintf("FAILURE: %Rrf (%Rrc)\n", rc, rc);
88 return rc;
89}
90
91static int NewImage(const char *pszFilename, uint32_t cMBs)
92{
93 RTPrintf("Creating VDI: file=\"%s\" size=%u MB...\n",
94 pszFilename, cMBs);
95
96 /* translate argv[] to UTF8 */
97 char *pszUtf8Filename;
98 int rc = FilenameToUtf8(&pszUtf8Filename, pszFilename);
99 if (VBOX_FAILURE(rc))
100 return rc;
101
102 rc = VDICreateBaseImage(pszUtf8Filename,
103 VDI_IMAGE_TYPE_NORMAL,
104 (uint64_t)cMBs * (uint64_t)(1024 * 1024),
105 "Newly created test image", NULL, NULL);
106 return PrintDone(rc);
107}
108
109static int ConvertDDImage(const char *pszFilename, const char *pszDDFilename)
110{
111 RTPrintf("Converting VDI: from DD image file=\"%s\" to file=\"%s\"...\n",
112 pszDDFilename, pszFilename);
113
114 /* translate argv[] to UTF8 */
115 char *pszUtf8Filename, *pszUtf8DDFilename;
116 int rc = FilenameToUtf8(&pszUtf8Filename, pszFilename);
117 if (VBOX_FAILURE(rc))
118 return rc;
119 rc = FilenameToUtf8(&pszUtf8DDFilename, pszDDFilename);
120 if (VBOX_FAILURE(rc))
121 return rc;
122
123 /* open raw image file. */
124 RTFILE File;
125 rc = RTFileOpen(&File, pszUtf8DDFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
126 if (VBOX_FAILURE(rc))
127 {
128 RTPrintf("File=\"%s\" open error: %Rrf\n", pszDDFilename, rc);
129 return rc;
130 }
131
132 /* get image size. */
133 uint64_t cbFile;
134 rc = RTFileGetSize(File, &cbFile);
135 if (VBOX_SUCCESS(rc))
136 {
137 RTPrintf("Creating fixed image with size %u Bytes...\n", (unsigned)cbFile);
138 rc = VDICreateBaseImage(pszUtf8Filename,
139 VDI_IMAGE_TYPE_FIXED,
140 cbFile,
141 "Converted from DD test image", NULL, NULL);
142 PrintDone(rc);
143 if (VBOX_SUCCESS(rc))
144 {
145 RTPrintf("Writing data...\n");
146 PVDIDISK pVdi = VDIDiskCreate();
147 rc = VDIDiskOpenImage(pVdi, pszUtf8Filename, VDI_OPEN_FLAGS_NORMAL);
148 if (VBOX_SUCCESS(rc))
149 {
150 /* alloc work buffer. */
151 void *pvBuf = RTMemAlloc(VDIDiskGetBufferSize(pVdi));
152 if (pvBuf)
153 {
154 uint64_t off = 0;
155 while (off < cbFile)
156 {
157 size_t cbRead = 0;
158 rc = RTFileRead(File, pvBuf, VDIDiskGetBufferSize(pVdi), &cbRead);
159 if (VBOX_FAILURE(rc) || !cbRead)
160 break;
161 rc = VDIDiskWrite(pVdi, off, pvBuf, cbRead);
162 if (VBOX_FAILURE(rc))
163 break;
164 off += cbRead;
165 }
166
167 RTMemFree(pvBuf);
168 }
169 else
170 rc = VERR_NO_MEMORY;
171
172 VDIDiskCloseImage(pVdi);
173 }
174
175 if (VBOX_FAILURE(rc))
176 {
177 /* delete image on error */
178 VDIDeleteImage(pszUtf8Filename);
179 }
180 PrintDone(rc);
181 }
182 }
183 RTFileClose(File);
184
185 return rc;
186}
187
188static DECLCALLBACK(int) ProcessCallback(PVM pVM, unsigned uPercent, void *pvUser)
189{
190 unsigned *pPercent = (unsigned *)pvUser;
191
192 if (*pPercent != uPercent)
193 {
194 *pPercent = uPercent;
195 RTPrintf(".");
196 if ((uPercent % 10) == 0 && uPercent)
197 RTPrintf("%d%%", uPercent);
198 RTStrmFlush(g_pStdOut);
199 }
200
201 return VINF_SUCCESS;
202}
203
204static int ConvertOldImage(const char *pszFilename)
205{
206 RTPrintf("Converting VDI image file=\"%s\" to a new format...\n"
207 "progress: 0%%",
208 pszFilename);
209
210 /* translate argv[] to UTF8 */
211 char *pszUtf8Filename;
212 int rc = FilenameToUtf8(&pszUtf8Filename, pszFilename);
213 if (VBOX_FAILURE(rc))
214 return rc;
215
216 unsigned uPercent = 0;
217 rc = VDIConvertImage(pszUtf8Filename, ProcessCallback, &uPercent);
218 RTPrintf("\n");
219 return PrintDone(rc);
220}
221
222static int DumpImage(const char *pszFilename)
223{
224 RTPrintf("Dumping VDI image file=\"%s\" into the log file...\n", pszFilename);
225 PVDIDISK pVdi = VDIDiskCreate();
226
227 /* translate argv[] to UTF8 */
228 char *pszUtf8Filename;
229 int rc = FilenameToUtf8(&pszUtf8Filename, pszFilename);
230 if (VBOX_FAILURE(rc))
231 return rc;
232 rc = VDIDiskOpenImage(pVdi, pszUtf8Filename, VDI_OPEN_FLAGS_READONLY);
233 if (VBOX_SUCCESS(rc))
234 {
235 VDIDiskDumpImages(pVdi);
236 VDIDiskCloseAllImages(pVdi);
237 }
238 return PrintDone(rc);
239}
240
241static int ResetImageGeometry(const char *pszFilename)
242{
243 RTPrintf("Resetting geometry info of VDI image file=\"%s\"\n", pszFilename);
244 PVDIDISK pVdi = VDIDiskCreate();
245
246 /* translate argv[] to UTF8 */
247 char *pszUtf8Filename;
248 int rc = FilenameToUtf8(&pszUtf8Filename, pszFilename);
249 if (VBOX_FAILURE(rc))
250 return rc;
251
252 rc = VDIDiskOpenImage(pVdi, pszUtf8Filename, VDI_OPEN_FLAGS_NORMAL);
253 if (VBOX_SUCCESS(rc))
254 {
255 PDMMEDIAGEOMETRY LCHSGeometry = {0, 0, 0};
256 rc = VDIDiskSetLCHSGeometry(pVdi, &LCHSGeometry);
257 }
258 VDIDiskCloseImage(pVdi);
259 return PrintDone(rc);
260}
261
262static int CopyImage(const char *pszDstFile, const char *pszSrcFile)
263{
264 RTPrintf("Copying VDI image file=\"%s\" to image file=\"%s\"...\n"
265 "progress: 0%%",
266 pszSrcFile, pszDstFile);
267
268 /* translate argv[] to UTF8 */
269 char *pszUtf8SrcFile, *pszUtf8DstFile;
270 int rc = FilenameToUtf8(&pszUtf8SrcFile, pszSrcFile);
271 if (VBOX_FAILURE(rc))
272 return rc;
273 rc = FilenameToUtf8(&pszUtf8DstFile, pszDstFile);
274 if (VBOX_FAILURE(rc))
275 return rc;
276
277 unsigned uPrecent = 0;
278 rc = VDICopyImage(pszUtf8DstFile, pszUtf8SrcFile, NULL, ProcessCallback, &uPrecent);
279 RTPrintf("\n");
280 return PrintDone(rc);
281}
282
283static int CopyToDD(const char *pszDstFile, const char *pszSrcFile)
284{
285 RTPrintf("Copying VDI image file=\"%s\" to DD file=\"%s\"...\n",
286 pszSrcFile, pszDstFile);
287 PVDIDISK pVdi = VDIDiskCreate();
288
289 /* translate argv[] to UTF8 */
290 char *pszUtf8SrcFile, *pszUtf8DstFile;
291 int rc = FilenameToUtf8(&pszUtf8SrcFile, pszSrcFile);
292 if (VBOX_FAILURE(rc))
293 return rc;
294 rc = FilenameToUtf8(&pszUtf8DstFile, pszDstFile);
295 if (VBOX_FAILURE(rc))
296 return rc;
297
298 rc = VDIDiskOpenImage(pVdi, pszUtf8SrcFile, VDI_OPEN_FLAGS_NORMAL);
299 if (VBOX_SUCCESS(rc))
300 {
301 RTFILE FileDst;
302 rc = RTFileOpen(&FileDst, pszUtf8DstFile, RTFILE_O_CREATE | RTFILE_O_READWRITE | RTFILE_O_DENY_WRITE);
303 if (VBOX_SUCCESS(rc))
304 {
305 uint64_t cbSrc = VDIDiskGetSize(pVdi);
306 const unsigned cbBuf = VDIDiskGetBlockSize(pVdi); /* or perhaps VDIDiskGetBufferSize(pVdi)? */
307 void *pvBuf = RTMemAlloc(cbBuf);
308 if (pvBuf)
309 {
310 uint64_t off = 0;
311 while (off < cbSrc)
312 {
313 rc = VDIDiskRead(pVdi, off, pvBuf, cbBuf);
314 if (VBOX_FAILURE(rc))
315 break;
316 rc = RTFileWrite(FileDst, pvBuf, cbBuf, NULL);
317 if (VBOX_FAILURE(rc))
318 break;
319 off += cbBuf;
320 }
321 RTMemFree(pvBuf);
322 }
323 RTFileClose(FileDst);
324 }
325 }
326 VDIDiskCloseImage(pVdi);
327 return PrintDone(rc);
328}
329
330static int ShrinkImage(const char *pszFilename)
331{
332 RTPrintf("Shrinking VDI image file=\"%s\"...\n"
333 "progress: 0%%",
334 pszFilename);
335
336 /* translate argv[] to UTF8 */
337 char *pszUtf8Filename;
338 int rc = FilenameToUtf8(&pszUtf8Filename, pszFilename);
339 if (VBOX_FAILURE(rc))
340 return rc;
341
342 unsigned uPrecent;
343 rc = VDIShrinkImage(pszUtf8Filename, ProcessCallback, &uPrecent);
344 RTPrintf("\n");
345 return PrintDone(rc);
346}
347
348int main(int argc, char **argv)
349{
350 putenv((char*)"VBOX_LOG_DEST=stdout");
351 putenv((char*)"VBOX_LOG_FLAGS=");
352
353 RTR3Init();
354 RTPrintf("vditool Copyright (c) 2004-2008 innotek GmbH.\n\n");
355
356 /*
357 * Do cmd line parsing.
358 */
359 if (argc < 2)
360 return UsageExit();
361
362 char szCmd[16];
363 if (strlen(argv[1]) >= sizeof(szCmd))
364 return SyntaxError("Invalid command!");
365 strcpy(szCmd, argv[1]);
366 ascii2upper(szCmd);
367
368 PRTLOGGER pLogger;
369 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
370 int rc = RTLogCreate(&pLogger, 0, "all",
371 NULL, ELEMENTS(s_apszGroups), s_apszGroups,
372 RTLOGDEST_STDOUT, NULL);
373 RTLogRelSetDefaultInstance(pLogger);
374
375 if (strcmp(szCmd, "NEW") == 0)
376 {
377 if (argc != 4)
378 return SyntaxError("Invalid argument count!");
379
380 uint32_t cMBs;
381 rc = RTStrToUInt32Ex(argv[3], NULL, 10, &cMBs);
382 if (VBOX_FAILURE(rc))
383 return SyntaxError("Invalid number!");
384 if ( cMBs < 2
385 || cMBs > 1024*1024)
386 {
387 RTPrintf("error: Disk size %RU32 (MB) is not within the range %u-%u!\n",
388 cMBs, 2, 1024*1024);
389 return 1;
390 }
391
392 rc = NewImage(argv[2], cMBs);
393 }
394 else if (strcmp(szCmd, "DD") == 0)
395 {
396 if (argc != 4)
397 return SyntaxError("Invalid argument count!");
398 rc = ConvertDDImage(argv[2], argv[3]);
399 }
400 else if (strcmp(szCmd, "CONVERT") == 0)
401 {
402 if (argc != 3)
403 return SyntaxError("Invalid argument count!");
404 rc = ConvertOldImage(argv[2]);
405 }
406 else if (strcmp(szCmd, "DUMP") == 0)
407 {
408 if (argc != 3)
409 return SyntaxError("Invalid argument count!");
410 rc = DumpImage(argv[2]);
411 }
412 else if (strcmp(szCmd, "RESETGEO") == 0)
413 {
414 if (argc != 3)
415 return SyntaxError("Invalid argument count!");
416 rc = ResetImageGeometry(argv[2]);
417 }
418 else if (strcmp(szCmd, "COPY") == 0)
419 {
420 if (argc != 4)
421 return SyntaxError("Invalid argument count!");
422 rc = CopyImage(argv[3], argv[2]);
423 }
424 else if (strcmp(szCmd, "COPYDD") == 0)
425 {
426 if (argc != 4)
427 return SyntaxError("Invalid argument count!");
428 rc = CopyToDD(argv[3], argv[2]);
429 }
430 else if (strcmp(szCmd, "SHRINK") == 0)
431 {
432 if (argc != 3)
433 return SyntaxError("Invalid argument count!");
434 rc = ShrinkImage(argv[2]);
435 }
436 else
437 return SyntaxError("Invalid command!");
438
439 RTLogFlush(NULL);
440 return !VBOX_SUCCESS(rc);
441}
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