VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use