VirtualBox

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

Last change on this file since 38469 was 38469, checked in by vboxsync, 13 years ago

VD: Interface cleanup. Merge the two involved structures (generic interface descriptor and callback table) into one, remove the duplicated interface wrappers in the backends and move the interface definitions into separate headers separating public and private interfaces.

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