VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/testcase/tstVD.cpp@ 17995

Last change on this file since 17995 was 17970, checked in by vboxsync, 16 years ago

API/HardDisk, Storage/VBoxHDD, Frontend/VBoxManage: eliminated base image type, which led to much unnecessary code duplication. Was triggered by VBoxManage finally being able to create all image variants the backends can support.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.6 KB
Line 
1/** @file
2 *
3 * Simple VBox HDD container test utility.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include <VBox/VBoxHDD.h>
23#include <VBox/err.h>
24#include <VBox/log.h>
25#include <iprt/asm.h>
26#include <iprt/dir.h>
27#include <iprt/string.h>
28#include <iprt/stream.h>
29#include <iprt/file.h>
30#include <iprt/mem.h>
31#include <iprt/initterm.h>
32#include <iprt/rand.h>
33#include "stdio.h"
34#include "stdlib.h"
35
36#define VHD_TEST
37#define VDI_TEST
38#define VMDK_TEST
39
40/*******************************************************************************
41* Global Variables *
42*******************************************************************************/
43/** The error count. */
44unsigned g_cErrors = 0;
45
46
47static void tstVDError(void *pvUser, int rc, RT_SRC_POS_DECL,
48 const char *pszFormat, va_list va)
49{
50 g_cErrors++;
51 RTPrintf("tstVD: Error %Rrc at %s:%u (%s): ", rc, RT_SRC_POS_ARGS);
52 RTPrintfV(pszFormat, va);
53 RTPrintf("\n");
54}
55
56
57static int tstVDCreateDelete(const char *pszBackend, const char *pszFilename,
58 uint64_t cbSize, unsigned uFlags, bool fDelete)
59{
60 int rc;
61 PVBOXHDD pVD = NULL;
62 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
63 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
64 PVDINTERFACE pVDIfs = NULL;
65 VDINTERFACE VDIError;
66 VDINTERFACEERROR VDIErrorCallbacks;
67
68#define CHECK(str) \
69 do \
70 { \
71 RTPrintf("%s rc=%Rrc\n", str, rc); \
72 if (RT_FAILURE(rc)) \
73 { \
74 VDDestroy(pVD); \
75 return rc; \
76 } \
77 } while (0)
78
79 /* Create error interface. */
80 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
81 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
82 VDIErrorCallbacks.pfnError = tstVDError;
83
84 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
85 NULL, &pVDIfs);
86 AssertRC(rc);
87
88 rc = VDCreate(&VDIError, &pVD);
89 CHECK("VDCreate()");
90
91 rc = VDCreateBase(pVD, pszBackend, pszFilename, cbSize,
92 uFlags, "Test image", &PCHS, &LCHS, NULL,
93 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
94 CHECK("VDCreateBase()");
95
96 VDDumpImages(pVD);
97
98 VDClose(pVD, fDelete);
99 if (fDelete)
100 {
101 RTFILE File;
102 rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ);
103 if (RT_SUCCESS(rc))
104 {
105 RTFileClose(File);
106 return VERR_INTERNAL_ERROR;
107 }
108 }
109
110 VDDestroy(pVD);
111#undef CHECK
112 return 0;
113}
114
115static int tstVDOpenDelete(const char *pszBackend, const char *pszFilename)
116{
117 int rc;
118 PVBOXHDD pVD = NULL;
119 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
120 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
121 PVDINTERFACE pVDIfs = NULL;
122 VDINTERFACE VDIError;
123 VDINTERFACEERROR VDIErrorCallbacks;
124
125#define CHECK(str) \
126 do \
127 { \
128 RTPrintf("%s rc=%Rrc\n", str, rc); \
129 if (RT_FAILURE(rc)) \
130 { \
131 VDDestroy(pVD); \
132 return rc; \
133 } \
134 } while (0)
135
136 /* Create error interface. */
137 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
138 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
139 VDIErrorCallbacks.pfnError = tstVDError;
140
141 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
142 NULL, &pVDIfs);
143 AssertRC(rc);
144
145 rc = VDCreate(&VDIError, &pVD);
146 CHECK("VDCreate()");
147
148 rc = VDOpen(pVD, pszBackend, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
149 CHECK("VDOpen()");
150
151 VDDumpImages(pVD);
152
153 VDClose(pVD, true);
154 RTFILE File;
155 rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ);
156 if (RT_SUCCESS(rc))
157 {
158 RTFileClose(File);
159 return VERR_INTERNAL_ERROR;
160 }
161
162 VDDestroy(pVD);
163#undef CHECK
164 return 0;
165}
166
167
168#undef RTDECL
169#define RTDECL(x) static x
170
171/* Start of IPRT code */
172
173/**
174 * The following code is based on the work of George Marsaglia
175 * taken from
176 * http://groups.google.ws/group/comp.sys.sun.admin/msg/7c667186f6cbf354
177 * and
178 * http://groups.google.ws/group/comp.lang.c/msg/0e170777c6e79e8d
179 */
180
181/*
182A C version of a very very good 64-bit RNG is given below.
183You should be able to adapt it to your particular needs.
184
185It is based on the complimentary-multiple-with-carry
186sequence
187 x(n)=a*x(n-4)+carry mod 2^64-1,
188which works as follows:
189Assume a certain multiplier 'a' and a base 'b'.
190Given a current x value and a current carry 'c',
191form: t=a*x+c
192Then the new carry is c=floor(t/b)
193and the new x value is x = b-1-(t mod b).
194
195
196Ordinarily, for 32-bit mwc or cmwc sequences, the
197value t=a*x+c can be formed in 64 bits, then the new c
198is the top and the new x the bottom 32 bits (with a little
199fiddling when b=2^32-1 and cmwc rather than mwc.)
200
201
202To generate 64-bit x's, it is difficult to form
203t=a*x+c in 128 bits then get the new c and new x
204from the top and bottom halves.
205But if 'a' has a special form, for example,
206a=2^62+2^47+2 and b=2^64-1, then the new c and
207the new x can be formed with shifts, tests and +/-'s,
208again with a little fiddling because b=2^64-1 rather
209than 2^64. (The latter is not an optimal choice because,
210being a square, it cannot be a primitive root of the
211prime a*b^k+1, where 'k' is the 'lag':
212 x(n)=a*x(n-k)+carry mod b.)
213But the multiplier a=2^62+2^47+2 makes a*b^4+1 a prime for
214which b=2^64-1 is a primitive root, and getting the new x and
215new c can be done with arithmetic on integers the size of x.
216*/
217
218struct RndCtx
219{
220 uint64_t x;
221 uint64_t y;
222 uint64_t z;
223 uint64_t w;
224 uint64_t c;
225 uint32_t u32x;
226 uint32_t u32y;
227};
228typedef struct RndCtx RNDCTX;
229typedef RNDCTX *PRNDCTX;
230
231/**
232 * Initialize seeds.
233 *
234 * @remarks You should choose ANY 4 random 64-bit
235 * seeds x,y,z,w < 2^64-1 and a random seed c in
236 * 0<= c < a = 2^62+2^47+2.
237 * There are P=(2^62+2^46+2)*(2^64-1)^4 > 2^318 possible choices
238 * for seeds, the period of the RNG.
239 */
240RTDECL(int) RTPRandInit(PRNDCTX pCtx, uint32_t u32Seed)
241{
242 if (u32Seed == 0)
243 u32Seed = (uint32_t)(ASMReadTSC() >> 8);
244 /* Zero is not a good seed. */
245 if (u32Seed == 0)
246 u32Seed = 362436069;
247 pCtx->x = u32Seed;
248 pCtx->y = 17280675555674358941ULL;
249 pCtx->z = 6376492577913983186ULL;
250 pCtx->w = 9064188857900113776ULL;
251 pCtx->c = 123456789;
252 pCtx->u32x = 2282008;
253 pCtx->u32y = u32Seed;
254 return VINF_SUCCESS;
255}
256
257RTDECL(uint32_t) RTPRandGetSeedInfo(PRNDCTX pCtx)
258{
259 return pCtx->u32y;
260}
261
262/**
263 * Generate a 64-bit unsigned random number.
264 *
265 * @returns The pseudo random number.
266 */
267RTDECL(uint64_t) RTPRandU64(PRNDCTX pCtx)
268{
269 uint64_t t;
270 t = (pCtx->x<<47) + (pCtx->x<<62) + (pCtx->x<<1);
271 t += pCtx->c; t+= (t < pCtx->c);
272 pCtx->c = (t<pCtx->c) + (pCtx->x>>17) + (pCtx->x>>2) + (pCtx->x>>63);
273 pCtx->x = pCtx->y; pCtx->y = pCtx->z ; pCtx->z = pCtx->w;
274 return (pCtx->w = ~(t + pCtx->c)-1);
275}
276
277/**
278 * Generate a 64-bit unsigned pseudo random number in the set
279 * [u64First..u64Last].
280 *
281 * @returns The pseudo random number.
282 * @param u64First First number in the set.
283 * @param u64Last Last number in the set.
284 */
285RTDECL(uint64_t) RTPRandU64Ex(PRNDCTX pCtx, uint64_t u64First, uint64_t u64Last)
286{
287 if (u64First == 0 && u64Last == UINT64_MAX)
288 return RTPRandU64(pCtx);
289
290 uint64_t u64Tmp;
291 uint64_t u64Range = u64Last - u64First + 1;
292 uint64_t u64Scale = UINT64_MAX / u64Range;
293
294 do
295 {
296 u64Tmp = RTPRandU64(pCtx) / u64Scale;
297 } while (u64Tmp >= u64Range);
298 return u64First + u64Tmp;
299}
300
301/**
302 * Generate a 32-bit unsigned random number.
303 *
304 * @returns The pseudo random number.
305 */
306RTDECL(uint32_t) RTPRandU32(PRNDCTX pCtx)
307{
308 return ( pCtx->u32x = 69069 * pCtx->u32x + 123,
309 pCtx->u32y ^= pCtx->u32y<<13,
310 pCtx->u32y ^= pCtx->u32y>>17,
311 pCtx->u32y ^= pCtx->u32y<<5,
312 pCtx->u32x + pCtx->u32y );
313}
314
315/**
316 * Generate a 32-bit unsigned pseudo random number in the set
317 * [u32First..u32Last].
318 *
319 * @returns The pseudo random number.
320 * @param u32First First number in the set.
321 * @param u32Last Last number in the set.
322 */
323RTDECL(uint32_t) RTPRandU32Ex(PRNDCTX pCtx, uint32_t u32First, uint32_t u32Last)
324{
325 if (u32First == 0 && u32Last == UINT32_MAX)
326 return RTPRandU32(pCtx);
327
328 uint32_t u32Tmp;
329 uint32_t u32Range = u32Last - u32First + 1;
330 uint32_t u32Scale = UINT32_MAX / u32Range;
331
332 do
333 {
334 u32Tmp = RTPRandU32(pCtx) / u32Scale;
335 } while (u32Tmp >= u32Range);
336 return u32First + u32Tmp;
337}
338
339/* End of IPRT code */
340
341struct Segment
342{
343 uint64_t u64Offset;
344 uint32_t u32Length;
345 uint32_t u8Value;
346};
347typedef struct Segment *PSEGMENT;
348
349static void initializeRandomGenerator(PRNDCTX pCtx, uint32_t u32Seed)
350{
351 int rc = RTPRandInit(pCtx, u32Seed);
352 if (RT_FAILURE(rc))
353 RTPrintf("ERROR: Failed to initialize random generator. RC=%Rrc\n", rc);
354 else
355 {
356 RTPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx));
357 RTLogPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx));
358 }
359}
360
361static int compareSegments(const void *left, const void *right)
362{
363 /* Note that no duplicates are allowed in the array being sorted. */
364 return ((PSEGMENT)left)->u64Offset < ((PSEGMENT)right)->u64Offset ? -1 : 1;
365}
366
367static void generateRandomSegments(PRNDCTX pCtx, PSEGMENT pSegment, uint32_t nSegments, uint32_t u32MaxSegmentSize, uint64_t u64DiskSize, uint32_t u32SectorSize, uint8_t u8ValueLow, uint8_t u8ValueHigh)
368{
369 uint32_t i;
370 /* Generate segment offsets. */
371 for (i = 0; i < nSegments; i++)
372 {
373 bool fDuplicateFound;
374 do
375 {
376 pSegment[i].u64Offset = RTPRandU64Ex(pCtx, 0, u64DiskSize / u32SectorSize - 1) * u32SectorSize;
377 fDuplicateFound = false;
378 for (uint32_t j = 0; j < i; j++)
379 if (pSegment[i].u64Offset == pSegment[j].u64Offset)
380 {
381 fDuplicateFound = true;
382 break;
383 }
384 } while (fDuplicateFound);
385 }
386 /* Sort in offset-ascending order. */
387 qsort(pSegment, nSegments, sizeof(*pSegment), compareSegments);
388 /* Put a sentinel at the end. */
389 pSegment[nSegments].u64Offset = u64DiskSize;
390 pSegment[nSegments].u32Length = 0;
391 /* Generate segment lengths and values. */
392 for (i = 0; i < nSegments; i++)
393 {
394 pSegment[i].u32Length = RTPRandU32Ex(pCtx, 1, RT_MIN(pSegment[i+1].u64Offset - pSegment[i].u64Offset,
395 u32MaxSegmentSize) / u32SectorSize) * u32SectorSize;
396 Assert(pSegment[i].u32Length <= u32MaxSegmentSize);
397 pSegment[i].u8Value = RTPRandU32Ex(pCtx, (uint32_t)u8ValueLow, (uint32_t)u8ValueHigh);
398 }
399}
400
401static void mergeSegments(PSEGMENT pBaseSegment, PSEGMENT pDiffSegment, PSEGMENT pMergeSegment, uint32_t u32MaxLength)
402{
403 while (pBaseSegment->u32Length > 0 || pDiffSegment->u32Length > 0)
404 {
405 if (pBaseSegment->u64Offset < pDiffSegment->u64Offset)
406 {
407 *pMergeSegment = *pBaseSegment;
408 if (pMergeSegment->u64Offset + pMergeSegment->u32Length <= pDiffSegment->u64Offset)
409 pBaseSegment++;
410 else
411 {
412 pMergeSegment->u32Length = pDiffSegment->u64Offset - pMergeSegment->u64Offset;
413 Assert(pMergeSegment->u32Length <= u32MaxLength);
414 if (pBaseSegment->u64Offset + pBaseSegment->u32Length >
415 pDiffSegment->u64Offset + pDiffSegment->u32Length)
416 {
417 pBaseSegment->u32Length -= pDiffSegment->u64Offset + pDiffSegment->u32Length - pBaseSegment->u64Offset;
418 Assert(pBaseSegment->u32Length <= u32MaxLength);
419 pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length;
420 }
421 else
422 pBaseSegment++;
423 }
424 pMergeSegment++;
425 }
426 else
427 {
428 *pMergeSegment = *pDiffSegment;
429 if (pMergeSegment->u64Offset + pMergeSegment->u32Length <= pBaseSegment->u64Offset)
430 {
431 pDiffSegment++;
432 pMergeSegment++;
433 }
434 else
435 {
436 if (pBaseSegment->u64Offset + pBaseSegment->u32Length > pDiffSegment->u64Offset + pDiffSegment->u32Length)
437 {
438 pBaseSegment->u32Length -= pDiffSegment->u64Offset + pDiffSegment->u32Length - pBaseSegment->u64Offset;
439 Assert(pBaseSegment->u32Length <= u32MaxLength);
440 pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length;
441 pDiffSegment++;
442 pMergeSegment++;
443 }
444 else
445 pBaseSegment++;
446 }
447 }
448 }
449}
450
451static void writeSegmentsToDisk(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment)
452{
453 while (pSegment->u32Length)
454 {
455 //memset((uint8_t*)pvBuf + pSegment->u64Offset, pSegment->u8Value, pSegment->u32Length);
456 memset(pvBuf, pSegment->u8Value, pSegment->u32Length);
457 VDWrite(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length);
458 pSegment++;
459 }
460}
461
462static int readAndCompareSegments(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment)
463{
464 while (pSegment->u32Length)
465 {
466 int rc = VDRead(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length);
467 if (RT_FAILURE(rc))
468 {
469 RTPrintf("ERROR: Failed to read from virtual disk\n");
470 return rc;
471 }
472 else
473 {
474 for (unsigned i = 0; i < pSegment->u32Length; i++)
475 if (((uint8_t*)pvBuf)[i] != pSegment->u8Value)
476 {
477 RTPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n",
478 pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i],
479 pSegment->u8Value);
480 RTLogPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n",
481 pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i],
482 pSegment->u8Value);
483 return VERR_INTERNAL_ERROR;
484 }
485 }
486 pSegment++;
487 }
488
489 return VINF_SUCCESS;
490}
491
492static int tstVDOpenCreateWriteMerge(const char *pszBackend,
493 const char *pszBaseFilename,
494 const char *pszDiffFilename,
495 uint32_t u32Seed)
496{
497 int rc;
498 PVBOXHDD pVD = NULL;
499 char *pszFormat;
500 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
501 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
502 uint64_t u64DiskSize = 1000 * _1M;
503 uint32_t u32SectorSize = 512;
504 PVDINTERFACE pVDIfs = NULL;
505 VDINTERFACE VDIError;
506 VDINTERFACEERROR VDIErrorCallbacks;
507
508#define CHECK(str) \
509 do \
510 { \
511 RTPrintf("%s rc=%Rrc\n", str, rc); \
512 if (RT_FAILURE(rc)) \
513 { \
514 if (pvBuf) \
515 RTMemFree(pvBuf); \
516 VDDestroy(pVD); \
517 return rc; \
518 } \
519 } while (0)
520
521 void *pvBuf = RTMemAlloc(_1M);
522
523 /* Create error interface. */
524 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
525 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
526 VDIErrorCallbacks.pfnError = tstVDError;
527
528 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
529 NULL, &pVDIfs);
530 AssertRC(rc);
531
532
533 rc = VDCreate(&VDIError, &pVD);
534 CHECK("VDCreate()");
535
536 RTFILE File;
537 rc = RTFileOpen(&File, pszBaseFilename, RTFILE_O_READ);
538 if (RT_SUCCESS(rc))
539 {
540 RTFileClose(File);
541 rc = VDGetFormat(pszBaseFilename, &pszFormat);
542 RTPrintf("VDGetFormat() pszFormat=%s rc=%Rrc\n", pszFormat, rc);
543 if (RT_SUCCESS(rc) && strcmp(pszFormat, pszBackend))
544 {
545 rc = VERR_GENERAL_FAILURE;
546 RTPrintf("VDGetFormat() returned incorrect backend name\n");
547 }
548 RTStrFree(pszFormat);
549 CHECK("VDGetFormat()");
550
551 rc = VDOpen(pVD, pszBackend, pszBaseFilename, VD_OPEN_FLAGS_NORMAL,
552 NULL);
553 CHECK("VDOpen()");
554 }
555 else
556 {
557 rc = VDCreateBase(pVD, pszBackend, pszBaseFilename, u64DiskSize,
558 VD_IMAGE_FLAGS_NONE, "Test image",
559 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
560 NULL, NULL);
561 CHECK("VDCreateBase()");
562 }
563
564 int nSegments = 100;
565 /* Allocate one extra element for a sentinel. */
566 PSEGMENT paBaseSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
567 PSEGMENT paDiffSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
568 PSEGMENT paMergeSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1) * 3);
569
570 RNDCTX ctx;
571 initializeRandomGenerator(&ctx, u32Seed);
572 generateRandomSegments(&ctx, paBaseSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u);
573 generateRandomSegments(&ctx, paDiffSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 128u, 255u);
574
575 /*PSEGMENT pSegment;
576 RTPrintf("Base segments:\n");
577 for (pSegment = paBaseSegments; pSegment->u32Length; pSegment++)
578 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
579 writeSegmentsToDisk(pVD, pvBuf, paBaseSegments);
580
581 rc = VDCreateDiff(pVD, pszBackend, pszDiffFilename,
582 VD_IMAGE_FLAGS_NONE, "Test diff image", NULL, NULL,
583 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
584 CHECK("VDCreateDiff()");
585
586 /*RTPrintf("\nDiff segments:\n");
587 for (pSegment = paDiffSegments; pSegment->u32Length; pSegment++)
588 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
589 writeSegmentsToDisk(pVD, pvBuf, paDiffSegments);
590
591 VDDumpImages(pVD);
592
593 RTPrintf("Merging diff into base..\n");
594 rc = VDMerge(pVD, VD_LAST_IMAGE, 0, NULL);
595 CHECK("VDMerge()");
596
597 mergeSegments(paBaseSegments, paDiffSegments, paMergeSegments, _1M);
598 /*RTPrintf("\nMerged segments:\n");
599 for (pSegment = paMergeSegments; pSegment->u32Length; pSegment++)
600 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
601 rc = readAndCompareSegments(pVD, pvBuf, paMergeSegments);
602 CHECK("readAndCompareSegments()");
603
604 RTMemFree(paMergeSegments);
605 RTMemFree(paDiffSegments);
606 RTMemFree(paBaseSegments);
607
608 VDDumpImages(pVD);
609
610 VDDestroy(pVD);
611 if (pvBuf)
612 RTMemFree(pvBuf);
613#undef CHECK
614 return 0;
615}
616
617static int tstVDCreateWriteOpenRead(const char *pszBackend,
618 const char *pszFilename,
619 uint32_t u32Seed)
620{
621 int rc;
622 PVBOXHDD pVD = NULL;
623 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
624 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
625 uint64_t u64DiskSize = 1000 * _1M;
626 uint32_t u32SectorSize = 512;
627 PVDINTERFACE pVDIfs;
628 VDINTERFACE VDIError;
629 VDINTERFACEERROR VDIErrorCallbacks;
630
631#define CHECK(str) \
632 do \
633 { \
634 RTPrintf("%s rc=%Rrc\n", str, rc); \
635 if (RT_FAILURE(rc)) \
636 { \
637 if (pvBuf) \
638 RTMemFree(pvBuf); \
639 VDDestroy(pVD); \
640 return rc; \
641 } \
642 } while (0)
643
644 void *pvBuf = RTMemAlloc(_1M);
645
646 /* Create error interface. */
647 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
648 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
649 VDIErrorCallbacks.pfnError = tstVDError;
650
651 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
652 NULL, &pVDIfs);
653 AssertRC(rc);
654
655
656 rc = VDCreate(&VDIError, &pVD);
657 CHECK("VDCreate()");
658
659 RTFILE File;
660 rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ);
661 if (RT_SUCCESS(rc))
662 {
663 RTFileClose(File);
664 RTFileDelete(pszFilename);
665 }
666
667 rc = VDCreateBase(pVD, pszBackend, pszFilename, u64DiskSize,
668 VD_IMAGE_FLAGS_NONE, "Test image",
669 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
670 NULL, NULL);
671 CHECK("VDCreateBase()");
672
673 int nSegments = 100;
674 /* Allocate one extra element for a sentinel. */
675 PSEGMENT paSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
676
677 RNDCTX ctx;
678 initializeRandomGenerator(&ctx, u32Seed);
679 generateRandomSegments(&ctx, paSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u);
680 /*for (PSEGMENT pSegment = paSegments; pSegment->u32Length; pSegment++)
681 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
682
683 writeSegmentsToDisk(pVD, pvBuf, paSegments);
684
685 VDCloseAll(pVD);
686
687 rc = VDOpen(pVD, pszBackend, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
688 CHECK("VDOpen()");
689 rc = readAndCompareSegments(pVD, pvBuf, paSegments);
690 CHECK("readAndCompareSegments()");
691
692 RTMemFree(paSegments);
693
694 VDDestroy(pVD);
695 if (pvBuf)
696 RTMemFree(pvBuf);
697#undef CHECK
698 return 0;
699}
700
701static int tstVmdkRename(const char *src, const char *dst)
702{
703 int rc;
704 PVBOXHDD pVD = NULL;
705 PVDINTERFACE pVDIfs = NULL;
706 VDINTERFACE VDIError;
707 VDINTERFACEERROR VDIErrorCallbacks;
708
709#define CHECK(str) \
710 do \
711 { \
712 RTPrintf("%s rc=%Rrc\n", str, rc); \
713 if (RT_FAILURE(rc)) \
714 { \
715 VDDestroy(pVD); \
716 return rc; \
717 } \
718 } while (0)
719
720 /* Create error interface. */
721 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
722 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
723 VDIErrorCallbacks.pfnError = tstVDError;
724
725 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
726 NULL, &pVDIfs);
727 AssertRC(rc);
728
729 rc = VDCreate(&VDIError, &pVD);
730 CHECK("VDCreate()");
731
732 rc = VDOpen(pVD, "VMDK", src, VD_OPEN_FLAGS_NORMAL, NULL);
733 CHECK("VDOpen()");
734 rc = VDCopy(pVD, 0, pVD, "VMDK", dst, true, 0, VD_IMAGE_FLAGS_NONE, NULL, NULL, NULL, NULL);
735 CHECK("VDCopy()");
736
737 VDDestroy(pVD);
738#undef CHECK
739 return 0;
740}
741
742static int tstVmdkCreateRenameOpen(const char *src, const char *dst,
743 uint64_t cbSize, unsigned uFlags)
744{
745 int rc = tstVDCreateDelete("VMDK", src, cbSize, uFlags, false);
746 if (RT_FAILURE(rc))
747 return rc;
748
749 rc = tstVmdkRename(src, dst);
750 if (RT_FAILURE(rc))
751 return rc;
752
753 PVBOXHDD pVD = NULL;
754 PVDINTERFACE pVDIfs = NULL;
755 VDINTERFACE VDIError;
756 VDINTERFACEERROR VDIErrorCallbacks;
757
758#define CHECK(str) \
759 do \
760 { \
761 RTPrintf("%s rc=%Rrc\n", str, rc); \
762 if (RT_FAILURE(rc)) \
763 { \
764 VDCloseAll(pVD); \
765 return rc; \
766 } \
767 } while (0)
768
769 /* Create error interface. */
770 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
771 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
772 VDIErrorCallbacks.pfnError = tstVDError;
773
774 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
775 NULL, &pVDIfs);
776 AssertRC(rc);
777
778 rc = VDCreate(&VDIError, &pVD);
779 CHECK("VDCreate()");
780
781 rc = VDOpen(pVD, "VMDK", dst, VD_OPEN_FLAGS_NORMAL, NULL);
782 CHECK("VDOpen()");
783
784 VDClose(pVD, true);
785 CHECK("VDClose()");
786 VDDestroy(pVD);
787#undef CHECK
788 return rc;
789}
790
791#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
792#define DST_PATH "tmp\\tmpVDRename.vmdk"
793#else
794#define DST_PATH "tmp/tmpVDRename.vmdk"
795#endif
796
797static void tstVmdk()
798{
799 int rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", "tmpVDRename.vmdk", _4G,
800 VD_IMAGE_FLAGS_NONE);
801 if (RT_FAILURE(rc))
802 {
803 RTPrintf("tstVD: VMDK rename (single extent, embedded descriptor, same dir) test failed! rc=%Rrc\n", rc);
804 g_cErrors++;
805 }
806 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", "tmpVDRename.vmdk", _4G,
807 VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
808 if (RT_FAILURE(rc))
809 {
810 RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, same dir) test failed! rc=%Rrc\n", rc);
811 g_cErrors++;
812 }
813 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
814 VD_IMAGE_FLAGS_NONE);
815 if (RT_FAILURE(rc))
816 {
817 RTPrintf("tstVD: VMDK rename (single extent, embedded descriptor, another dir) test failed! rc=%Rrc\n", rc);
818 g_cErrors++;
819 }
820 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
821 VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
822 if (RT_FAILURE(rc))
823 {
824 RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, another dir) test failed! rc=%Rrc\n", rc);
825 g_cErrors++;
826 }
827
828 RTFILE File;
829 rc = RTFileOpen(&File, DST_PATH, RTFILE_O_CREATE | RTFILE_O_WRITE);
830 if (RT_SUCCESS(rc))
831 RTFileClose(File);
832
833 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
834 VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
835 if (RT_SUCCESS(rc))
836 {
837 RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, another dir, already exists) test failed!\n");
838 g_cErrors++;
839 }
840 RTFileDelete(DST_PATH);
841 RTFileDelete("tmpVDCreate.vmdk");
842 RTFileDelete("tmpVDCreate-s001.vmdk");
843 RTFileDelete("tmpVDCreate-s002.vmdk");
844 RTFileDelete("tmpVDCreate-s003.vmdk");
845}
846
847int main(int argc, char *argv[])
848{
849 RTR3Init();
850 int rc;
851
852 uint32_t u32Seed = 0; // Means choose random
853
854 if (argc > 1)
855 if (sscanf(argv[1], "%x", &u32Seed) != 1)
856 {
857 RTPrintf("ERROR: Invalid parameter %s. Valid usage is %s <32-bit seed>.\n",
858 argv[1], argv[0]);
859 return 1;
860 }
861
862 RTPrintf("tstVD: TESTING...\n");
863
864 /*
865 * Clean up potential leftovers from previous unsuccessful runs.
866 */
867 RTFileDelete("tmpVDCreate.vdi");
868 RTFileDelete("tmpVDCreate.vmdk");
869 RTFileDelete("tmpVDCreate.vhd");
870 RTFileDelete("tmpVDBase.vdi");
871 RTFileDelete("tmpVDDiff.vdi");
872 RTFileDelete("tmpVDBase.vmdk");
873 RTFileDelete("tmpVDDiff.vmdk");
874 RTFileDelete("tmpVDBase.vhd");
875 RTFileDelete("tmpVDDiff.vhd");
876 RTFileDelete("tmpVDCreate-s001.vmdk");
877 RTFileDelete("tmpVDCreate-s002.vmdk");
878 RTFileDelete("tmpVDCreate-s003.vmdk");
879 RTFileDelete("tmpVDRename.vmdk");
880 RTFileDelete("tmpVDRename-s001.vmdk");
881 RTFileDelete("tmpVDRename-s002.vmdk");
882 RTFileDelete("tmpVDRename-s003.vmdk");
883 RTFileDelete("tmp/tmpVDRename.vmdk");
884 RTFileDelete("tmp/tmpVDRename-s001.vmdk");
885 RTFileDelete("tmp/tmpVDRename-s002.vmdk");
886 RTFileDelete("tmp/tmpVDRename-s003.vmdk");
887
888 if (!RTDirExists("tmp"))
889 {
890 rc = RTDirCreate("tmp", RTFS_UNIX_IRWXU);
891 if (RT_FAILURE(rc))
892 {
893 RTPrintf("tstVD: Failed to create 'tmp' directory! rc=%Rrc\n", rc);
894 g_cErrors++;
895 }
896 }
897
898#ifdef VMDK_TEST
899 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
900 VD_IMAGE_FLAGS_NONE, true);
901 if (RT_FAILURE(rc))
902 {
903 RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
904 g_cErrors++;
905 }
906 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
907 VD_IMAGE_FLAGS_NONE, false);
908 if (RT_FAILURE(rc))
909 {
910 RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
911 g_cErrors++;
912 }
913 rc = tstVDOpenDelete("VMDK", "tmpVDCreate.vmdk");
914 if (RT_FAILURE(rc))
915 {
916 RTPrintf("tstVD: VMDK delete test failed! rc=%Rrc\n", rc);
917 g_cErrors++;
918 }
919
920 tstVmdk();
921#endif /* VMDK_TEST */
922#ifdef VDI_TEST
923 rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
924 VD_IMAGE_FLAGS_NONE, true);
925 if (RT_FAILURE(rc))
926 {
927 RTPrintf("tstVD: dynamic VDI create test failed! rc=%Rrc\n", rc);
928 g_cErrors++;
929 }
930 rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
931 VD_IMAGE_FLAGS_NONE, true);
932 if (RT_FAILURE(rc))
933 {
934 RTPrintf("tstVD: fixed VDI create test failed! rc=%Rrc\n", rc);
935 g_cErrors++;
936 }
937#endif /* VDI_TEST */
938#ifdef VMDK_TEST
939 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
940 VD_IMAGE_FLAGS_NONE, true);
941 if (RT_FAILURE(rc))
942 {
943 RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
944 g_cErrors++;
945 }
946 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
947 VD_VMDK_IMAGE_FLAGS_SPLIT_2G, true);
948 if (RT_FAILURE(rc))
949 {
950 RTPrintf("tstVD: dynamic split VMDK create test failed! rc=%Rrc\n", rc);
951 g_cErrors++;
952 }
953 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
954 VD_IMAGE_FLAGS_FIXED, true);
955 if (RT_FAILURE(rc))
956 {
957 RTPrintf("tstVD: fixed VMDK create test failed! rc=%Rrc\n", rc);
958 g_cErrors++;
959 }
960 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
961 VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_SPLIT_2G,
962 true);
963 if (RT_FAILURE(rc))
964 {
965 RTPrintf("tstVD: fixed split VMDK create test failed! rc=%Rrc\n", rc);
966 g_cErrors++;
967 }
968#endif /* VMDK_TEST */
969#ifdef VHD_TEST
970 rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
971 VD_IMAGE_FLAGS_NONE, true);
972 if (RT_FAILURE(rc))
973 {
974 RTPrintf("tstVD: dynamic VHD create test failed! rc=%Rrc\n", rc);
975 g_cErrors++;
976 }
977 rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
978 VD_IMAGE_FLAGS_FIXED, true);
979 if (RT_FAILURE(rc))
980 {
981 RTPrintf("tstVD: fixed VHD create test failed! rc=%Rrc\n", rc);
982 g_cErrors++;
983 }
984#endif /* VHD_TEST */
985#ifdef VDI_TEST
986 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
987 if (RT_FAILURE(rc))
988 {
989 RTPrintf("tstVD: VDI test failed (new image)! rc=%Rrc\n", rc);
990 g_cErrors++;
991 }
992 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
993 if (RT_FAILURE(rc))
994 {
995 RTPrintf("tstVD: VDI test failed (existing image)! rc=%Rrc\n", rc);
996 g_cErrors++;
997 }
998#endif /* VDI_TEST */
999#ifdef VMDK_TEST
1000 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
1001 if (RT_FAILURE(rc))
1002 {
1003 RTPrintf("tstVD: VMDK test failed (new image)! rc=%Rrc\n", rc);
1004 g_cErrors++;
1005 }
1006 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
1007 if (RT_FAILURE(rc))
1008 {
1009 RTPrintf("tstVD: VMDK test failed (existing image)! rc=%Rrc\n", rc);
1010 g_cErrors++;
1011 }
1012#endif /* VMDK_TEST */
1013#ifdef VHD_TEST
1014 rc = tstVDCreateWriteOpenRead("VHD", "tmpVDCreate.vhd", u32Seed);
1015 if (RT_FAILURE(rc))
1016 {
1017 RTPrintf("tstVD: VHD test failed (creating image)! rc=%Rrc\n", rc);
1018 g_cErrors++;
1019 }
1020
1021 rc = tstVDOpenCreateWriteMerge("VHD", "tmpVDBase.vhd", "tmpVDDiff.vhd", u32Seed);
1022 if (RT_FAILURE(rc))
1023 {
1024 RTPrintf("tstVD: VHD test failed (existing image)! rc=%Rrc\n", rc);
1025 g_cErrors++;
1026 }
1027#endif /* VHD_TEST */
1028
1029 /*
1030 * Clean up any leftovers.
1031 */
1032 RTFileDelete("tmpVDCreate.vdi");
1033 RTFileDelete("tmpVDCreate.vmdk");
1034 RTFileDelete("tmpVDCreate.vhd");
1035 RTFileDelete("tmpVDBase.vdi");
1036 RTFileDelete("tmpVDDiff.vdi");
1037 RTFileDelete("tmpVDBase.vmdk");
1038 RTFileDelete("tmpVDDiff.vmdk");
1039 RTFileDelete("tmpVDBase.vhd");
1040 RTFileDelete("tmpVDDiff.vhd");
1041 RTFileDelete("tmpVDCreate-s001.vmdk");
1042 RTFileDelete("tmpVDCreate-s002.vmdk");
1043 RTFileDelete("tmpVDCreate-s003.vmdk");
1044 RTFileDelete("tmpVDRename.vmdk");
1045 RTFileDelete("tmpVDRename-s001.vmdk");
1046 RTFileDelete("tmpVDRename-s002.vmdk");
1047 RTFileDelete("tmpVDRename-s003.vmdk");
1048
1049 rc = VDShutdown();
1050 if (RT_FAILURE(rc))
1051 {
1052 RTPrintf("tstVD: unloading backends failed! rc=%Rrc\n", rc);
1053 g_cErrors++;
1054 }
1055 /*
1056 * Summary
1057 */
1058 if (!g_cErrors)
1059 RTPrintf("tstVD: SUCCESS\n");
1060 else
1061 RTPrintf("tstVD: FAILURE - %d errors\n", g_cErrors);
1062
1063 return !!g_cErrors;
1064}
1065
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