VirtualBox

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

Last change on this file since 26988 was 26988, checked in by vboxsync, 15 years ago

Commit the correct file

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