VirtualBox

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

Last change on this file since 29250 was 29250, checked in by vboxsync, 14 years ago

iprt/asm*.h: split out asm-math.h, don't include asm-*.h from asm.h, don't include asm.h from sup.h. Fixed a couple file headers.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use