VirtualBox

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

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

VD: Move the generic virtual disk framework + backends to src/VBox/Storage and rename the files to get rid of the HDD part because it supports floppy and DVD images too

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