VirtualBox

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

Last change on this file since 11371 was 11353, checked in by vboxsync, 17 years ago

VBoxHDD-new: add new UUID parameter to image creation, specifying which UUID the new image should have.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.8 KB
Line 
1/** @file
2 *
3 * Simple VBox HDD container test utility.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include <VBox/err.h>
23#include <VBox/VBoxHDD-new.h>
24#include <iprt/string.h>
25#include <iprt/stream.h>
26#include <iprt/file.h>
27#include <iprt/mem.h>
28#include <iprt/initterm.h>
29#include <iprt/rand.h>
30#include "stdio.h"
31#include "stdlib.h"
32
33/*******************************************************************************
34* Global Variables *
35*******************************************************************************/
36/** The error count. */
37unsigned g_cErrors = 0;
38
39
40static void tstVDError(void *pvUser, int rc, RT_SRC_POS_DECL,
41 const char *pszFormat, va_list va)
42{
43 g_cErrors++;
44 RTPrintf("tstVD: Error %Vrc at %s:%u (%s): ", rc, RT_SRC_POS_ARGS);
45 RTPrintfV(pszFormat, va);
46 RTPrintf("\n");
47}
48
49
50static int tstVDCreateDelete(const char *pszBackend, const char *pszFilename,
51 uint64_t cbSize, VDIMAGETYPE enmType,
52 unsigned uFlags, bool fDelete)
53{
54 int rc;
55 PVBOXHDD pVD = NULL;
56 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
57 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
58 VDINTERFACE VDIError;
59 VDINTERFACEERROR VDIErrorCallbacks;
60
61#define CHECK(str) \
62 do \
63 { \
64 RTPrintf("%s rc=%Vrc\n", str, rc); \
65 if (VBOX_FAILURE(rc)) \
66 { \
67 VDCloseAll(pVD); \
68 return rc; \
69 } \
70 } while (0)
71
72 /* Create error interface. */
73 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
74 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
75 VDIErrorCallbacks.pfnError = tstVDError;
76
77 rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
78 NULL, NULL);
79 AssertRC(rc);
80
81 rc = VDCreate(&VDIError, &pVD);
82 CHECK("VDCreate()");
83
84 rc = VDCreateBase(pVD, pszBackend, pszFilename, enmType, cbSize,
85 uFlags, "Test image", &PCHS, &LCHS, NULL,
86 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
87 CHECK("VDCreateBase()");
88
89 VDDumpImages(pVD);
90
91 VDClose(pVD, fDelete);
92#undef CHECK
93 return 0;
94}
95
96
97#undef RTDECL
98#define RTDECL(x) static x
99
100/* Start of IPRT code */
101
102/**
103 * The following code is based on the work of George Marsaglia
104 * taken from
105 * http://groups.google.ws/group/comp.sys.sun.admin/msg/7c667186f6cbf354
106 * and
107 * http://groups.google.ws/group/comp.lang.c/msg/0e170777c6e79e8d
108 */
109
110/*
111A C version of a very very good 64-bit RNG is given below.
112You should be able to adapt it to your particular needs.
113
114It is based on the complimentary-multiple-with-carry
115sequence
116 x(n)=a*x(n-4)+carry mod 2^64-1,
117which works as follows:
118Assume a certain multiplier 'a' and a base 'b'.
119Given a current x value and a current carry 'c',
120form: t=a*x+c
121Then the new carry is c=floor(t/b)
122and the new x value is x = b-1-(t mod b).
123
124
125Ordinarily, for 32-bit mwc or cmwc sequences, the
126value t=a*x+c can be formed in 64 bits, then the new c
127is the top and the new x the bottom 32 bits (with a little
128fiddling when b=2^32-1 and cmwc rather than mwc.)
129
130
131To generate 64-bit x's, it is difficult to form
132t=a*x+c in 128 bits then get the new c and new x
133from the the top and bottom halves.
134But if 'a' has a special form, for example,
135a=2^62+2^47+2 and b=2^64-1, then the new c and
136the new x can be formed with shifts, tests and +/-'s,
137again with a little fiddling because b=2^64-1 rather
138than 2^64. (The latter is not an optimal choice because,
139being a square, it cannot be a primitive root of the
140prime a*b^k+1, where 'k' is the 'lag':
141 x(n)=a*x(n-k)+carry mod b.)
142But the multiplier a=2^62+2^47+2 makes a*b^4+1 a prime for
143which b=2^64-1 is a primitive root, and getting the new x and
144new c can be done with arithmetic on integers the size of x.
145*/
146
147struct RndCtx
148{
149 uint64_t x;
150 uint64_t y;
151 uint64_t z;
152 uint64_t w;
153 uint64_t c;
154 uint32_t u32x;
155 uint32_t u32y;
156};
157typedef struct RndCtx RNDCTX;
158typedef RNDCTX *PRNDCTX;
159
160/**
161 * Initialize seeds.
162 *
163 * @remarks You should choose ANY 4 random 64-bit
164 * seeds x,y,z,w < 2^64-1 and a random seed c in
165 * 0<= c < a = 2^62+2^47+2.
166 * There are P=(2^62+2^46+2)*(2^64-1)^4 > 2^318 possible choices
167 * for seeds, the period of the RNG.
168 */
169RTDECL(int) RTPRandInit(PRNDCTX pCtx, uint32_t u32Seed)
170{
171 if (u32Seed == 0)
172 u32Seed = (uint32_t)(ASMReadTSC() >> 8);
173 /* Zero is not a good seed. */
174 if (u32Seed == 0)
175 u32Seed = 362436069;
176 pCtx->x = u32Seed;
177 pCtx->y = 17280675555674358941ULL;
178 pCtx->z = 6376492577913983186ULL;
179 pCtx->w = 9064188857900113776ULL;
180 pCtx->c = 123456789;
181 pCtx->u32x = 2282008;
182 pCtx->u32y = u32Seed;
183 return VINF_SUCCESS;
184}
185
186RTDECL(uint32_t) RTPRandGetSeedInfo(PRNDCTX pCtx)
187{
188 return pCtx->u32y;
189}
190
191/**
192 * Generate a 64-bit unsigned random number.
193 *
194 * @returns The pseudo random number.
195 */
196RTDECL(uint64_t) RTPRandU64(PRNDCTX pCtx)
197{
198 uint64_t t;
199 t = (pCtx->x<<47) + (pCtx->x<<62) + (pCtx->x<<1);
200 t += pCtx->c; t+= (t < pCtx->c);
201 pCtx->c = (t<pCtx->c) + (pCtx->x>>17) + (pCtx->x>>2) + (pCtx->x>>63);
202 pCtx->x = pCtx->y; pCtx->y = pCtx->z ; pCtx->z = pCtx->w;
203 return (pCtx->w = ~(t + pCtx->c)-1);
204}
205
206/**
207 * Generate a 64-bit unsigned pseudo random number in the set
208 * [u64First..u64Last].
209 *
210 * @returns The pseudo random number.
211 * @param u64First First number in the set.
212 * @param u64Last Last number in the set.
213 */
214RTDECL(uint64_t) RTPRandU64Ex(PRNDCTX pCtx, uint64_t u64First, uint64_t u64Last)
215{
216 if (u64First == 0 && u64Last == UINT64_MAX)
217 return RTPRandU64(pCtx);
218
219 uint64_t u64Tmp;
220 uint64_t u64Range = u64Last - u64First + 1;
221 uint64_t u64Scale = UINT64_MAX / u64Range;
222
223 do
224 {
225 u64Tmp = RTPRandU64(pCtx) / u64Scale;
226 } while (u64Tmp >= u64Range);
227 return u64First + u64Tmp;
228}
229
230/**
231 * Generate a 32-bit unsigned random number.
232 *
233 * @returns The pseudo random number.
234 */
235RTDECL(uint32_t) RTPRandU32(PRNDCTX pCtx)
236{
237 return ( pCtx->u32x = 69069 * pCtx->u32x + 123,
238 pCtx->u32y ^= pCtx->u32y<<13,
239 pCtx->u32y ^= pCtx->u32y>>17,
240 pCtx->u32y ^= pCtx->u32y<<5,
241 pCtx->u32x + pCtx->u32y );
242}
243
244/**
245 * Generate a 32-bit unsigned pseudo random number in the set
246 * [u32First..u32Last].
247 *
248 * @returns The pseudo random number.
249 * @param u32First First number in the set.
250 * @param u32Last Last number in the set.
251 */
252RTDECL(uint32_t) RTPRandU32Ex(PRNDCTX pCtx, uint32_t u32First, uint32_t u32Last)
253{
254 if (u32First == 0 && u32Last == UINT32_MAX)
255 return RTPRandU32(pCtx);
256
257 uint32_t u32Tmp;
258 uint32_t u32Range = u32Last - u32First + 1;
259 uint32_t u32Scale = UINT32_MAX / u32Range;
260
261 do
262 {
263 u32Tmp = RTPRandU32(pCtx) / u32Scale;
264 } while (u32Tmp >= u32Range);
265 return u32First + u32Tmp;
266}
267
268/* End of IPRT code */
269
270struct Segment
271{
272 uint64_t u64Offset;
273 uint32_t u32Length;
274 uint32_t u8Value;
275};
276typedef struct Segment *PSEGMENT;
277
278static void initializeRandomGenerator(PRNDCTX pCtx, uint32_t u32Seed)
279{
280 int rc = RTPRandInit(pCtx, u32Seed);
281 if (VBOX_FAILURE(rc))
282 RTPrintf("ERROR: Failed to initialize random generator. RC=%Vrc\n", rc);
283 else
284 {
285 RTPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx));
286 RTLogPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx));
287 }
288}
289
290static int compareSegments(const void *left, const void *right)
291{
292 /* Note that no duplicates are allowed in the array being sorted. */
293 return ((PSEGMENT)left)->u64Offset < ((PSEGMENT)right)->u64Offset ? -1 : 1;
294}
295
296static void generateRandomSegments(PRNDCTX pCtx, PSEGMENT pSegment, uint32_t nSegments, uint32_t u32MaxSegmentSize, uint64_t u64DiskSize, uint32_t u32SectorSize, uint8_t u8ValueLow, uint8_t u8ValueHigh)
297{
298 uint32_t i;
299 /* Generate segment offsets. */
300 for (i = 0; i < nSegments; i++)
301 {
302 bool fDuplicateFound;
303 do
304 {
305 pSegment[i].u64Offset = RTPRandU64Ex(pCtx, 0, u64DiskSize / u32SectorSize - 1) * u32SectorSize;
306 fDuplicateFound = false;
307 for (uint32_t j = 0; j < i; j++)
308 if (pSegment[i].u64Offset == pSegment[j].u64Offset)
309 {
310 fDuplicateFound = true;
311 break;
312 }
313 } while (fDuplicateFound);
314 }
315 /* Sort in offset-ascending order. */
316 qsort(pSegment, nSegments, sizeof(*pSegment), compareSegments);
317 /* Put a sentinel at the end. */
318 pSegment[nSegments].u64Offset = u64DiskSize;
319 pSegment[nSegments].u32Length = 0;
320 /* Generate segment lengths and values. */
321 for (i = 0; i < nSegments; i++)
322 {
323 pSegment[i].u32Length = RTPRandU32Ex(pCtx, 1, RT_MIN(pSegment[i+1].u64Offset - pSegment[i].u64Offset,
324 u32MaxSegmentSize) / u32SectorSize) * u32SectorSize;
325 Assert(pSegment[i].u32Length <= u32MaxSegmentSize);
326 pSegment[i].u8Value = RTPRandU32Ex(pCtx, (uint32_t)u8ValueLow, (uint32_t)u8ValueHigh);
327 }
328}
329
330static void mergeSegments(PSEGMENT pBaseSegment, PSEGMENT pDiffSegment, PSEGMENT pMergeSegment, uint32_t u32MaxLength)
331{
332 while (pBaseSegment->u32Length > 0 || pDiffSegment->u32Length > 0)
333 {
334 if (pBaseSegment->u64Offset < pDiffSegment->u64Offset)
335 {
336 *pMergeSegment = *pBaseSegment;
337 if (pMergeSegment->u64Offset + pMergeSegment->u32Length <= pDiffSegment->u64Offset)
338 pBaseSegment++;
339 else
340 {
341 pMergeSegment->u32Length = pDiffSegment->u64Offset - pMergeSegment->u64Offset;
342 Assert(pMergeSegment->u32Length <= u32MaxLength);
343 if (pBaseSegment->u64Offset + pBaseSegment->u32Length >
344 pDiffSegment->u64Offset + pDiffSegment->u32Length)
345 {
346 pBaseSegment->u32Length -= pDiffSegment->u64Offset + pDiffSegment->u32Length - pBaseSegment->u64Offset;
347 Assert(pBaseSegment->u32Length <= u32MaxLength);
348 pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length;
349 }
350 else
351 pBaseSegment++;
352 }
353 pMergeSegment++;
354 }
355 else
356 {
357 *pMergeSegment = *pDiffSegment;
358 if (pMergeSegment->u64Offset + pMergeSegment->u32Length <= pBaseSegment->u64Offset)
359 {
360 pDiffSegment++;
361 pMergeSegment++;
362 }
363 else
364 {
365 if (pBaseSegment->u64Offset + pBaseSegment->u32Length > pDiffSegment->u64Offset + pDiffSegment->u32Length)
366 {
367 pBaseSegment->u32Length -= pDiffSegment->u64Offset + pDiffSegment->u32Length - pBaseSegment->u64Offset;
368 Assert(pBaseSegment->u32Length <= u32MaxLength);
369 pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length;
370 pDiffSegment++;
371 pMergeSegment++;
372 }
373 else
374 pBaseSegment++;
375 }
376 }
377 }
378}
379
380static void writeSegmentsToDisk(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment)
381{
382 while (pSegment->u32Length)
383 {
384 //memset((uint8_t*)pvBuf + pSegment->u64Offset, pSegment->u8Value, pSegment->u32Length);
385 memset(pvBuf, pSegment->u8Value, pSegment->u32Length);
386 VDWrite(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length);
387 pSegment++;
388 }
389}
390
391static int readAndCompareSegments(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment)
392{
393 while (pSegment->u32Length)
394 {
395 int rc = VDRead(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length);
396 if (VBOX_FAILURE(rc))
397 {
398 RTPrintf("ERROR: Failed to read from virtual disk\n");
399 return rc;
400 }
401 else
402 {
403 for (unsigned i = 0; i < pSegment->u32Length; i++)
404 if (((uint8_t*)pvBuf)[i] != pSegment->u8Value)
405 {
406 RTPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n",
407 pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i],
408 pSegment->u8Value);
409 RTLogPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n",
410 pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i],
411 pSegment->u8Value);
412 return VERR_INTERNAL_ERROR;
413 }
414 }
415 pSegment++;
416 }
417
418 return VINF_SUCCESS;
419}
420
421static int tstVDOpenCreateWriteMerge(const char *pszBackend,
422 const char *pszBaseFilename,
423 const char *pszDiffFilename,
424 uint32_t u32Seed)
425{
426 int rc;
427 PVBOXHDD pVD = NULL;
428 char *pszFormat;
429 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
430 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
431 uint64_t u64DiskSize = 1000 * _1M;
432 uint32_t u32SectorSize = 512;
433 VDINTERFACE VDIError;
434 VDINTERFACEERROR VDIErrorCallbacks;
435
436#define CHECK(str) \
437 do \
438 { \
439 RTPrintf("%s rc=%Vrc\n", str, rc); \
440 if (VBOX_FAILURE(rc)) \
441 { \
442 VDCloseAll(pVD); \
443 return rc; \
444 } \
445 } while (0)
446
447 /* Create error interface. */
448 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
449 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
450 VDIErrorCallbacks.pfnError = tstVDError;
451
452 rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
453 NULL, NULL);
454 AssertRC(rc);
455
456
457 rc = VDCreate(&VDIError, &pVD);
458 CHECK("VDCreate()");
459
460 RTFILE File;
461 rc = RTFileOpen(&File, pszBaseFilename, RTFILE_O_READ);
462 if (VBOX_SUCCESS(rc))
463 {
464 RTFileClose(File);
465 rc = VDGetFormat(pszBaseFilename, &pszFormat);
466 RTPrintf("VDGetFormat() pszFormat=%s rc=%Vrc\n", pszFormat, rc);
467 if (VBOX_SUCCESS(rc) && strcmp(pszFormat, pszBackend))
468 {
469 rc = VERR_GENERAL_FAILURE;
470 RTPrintf("VDGetFormat() returned incorrect backend name\n");
471 }
472 RTStrFree(pszFormat);
473 CHECK("VDGetFormat()");
474
475 rc = VDOpen(pVD, pszBackend, pszBaseFilename, VD_OPEN_FLAGS_NORMAL);
476 CHECK("VDOpen()");
477 }
478 else
479 {
480 rc = VDCreateBase(pVD, pszBackend, pszBaseFilename,
481 VD_IMAGE_TYPE_NORMAL, u64DiskSize,
482 VD_IMAGE_FLAGS_NONE, "Test image",
483 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
484 NULL, NULL);
485 CHECK("VDCreateBase()");
486 }
487
488 int nSegments = 100;
489 /* Allocate one extra element for a sentinel. */
490 PSEGMENT paBaseSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
491 PSEGMENT paDiffSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
492 PSEGMENT paMergeSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1) * 3);
493
494 void *pvBuf = RTMemAlloc(_1M);
495
496 RNDCTX ctx;
497 initializeRandomGenerator(&ctx, u32Seed);
498 generateRandomSegments(&ctx, paBaseSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u);
499 generateRandomSegments(&ctx, paDiffSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 128u, 255u);
500
501 /*PSEGMENT pSegment;
502 RTPrintf("Base segments:\n");
503 for (pSegment = paBaseSegments; pSegment->u32Length; pSegment++)
504 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
505 writeSegmentsToDisk(pVD, pvBuf, paBaseSegments);
506
507 rc = VDCreateDiff(pVD, pszBackend, pszDiffFilename,
508 VD_IMAGE_FLAGS_NONE, "Test diff image", NULL,
509 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
510 CHECK("VDCreateDiff()");
511
512 /*RTPrintf("\nDiff segments:\n");
513 for (pSegment = paDiffSegments; pSegment->u32Length; pSegment++)
514 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
515 writeSegmentsToDisk(pVD, pvBuf, paDiffSegments);
516
517 VDDumpImages(pVD);
518
519 RTPrintf("Merging diff into base..\n");
520 rc = VDMerge(pVD, (unsigned)-1, 0, NULL, NULL);
521 CHECK("VDMerge()");
522
523 mergeSegments(paBaseSegments, paDiffSegments, paMergeSegments, _1M);
524 /*RTPrintf("\nMerged segments:\n");
525 for (pSegment = paMergeSegments; pSegment->u32Length; pSegment++)
526 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
527 rc = readAndCompareSegments(pVD, pvBuf, paMergeSegments);
528 CHECK("readAndCompareSegments()");
529
530 RTMemFree(paMergeSegments);
531 RTMemFree(paDiffSegments);
532 RTMemFree(paBaseSegments);
533
534 VDDumpImages(pVD);
535
536 VDCloseAll(pVD);
537#undef CHECK
538 return 0;
539}
540
541static int tstVDCreateWriteOpenRead(const char *pszBackend,
542 const char *pszFilename,
543 uint32_t u32Seed)
544{
545 int rc;
546 PVBOXHDD pVD = NULL;
547 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
548 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
549 uint64_t u64DiskSize = 1000 * _1M;
550 uint32_t u32SectorSize = 512;
551 VDINTERFACE VDIError;
552 VDINTERFACEERROR VDIErrorCallbacks;
553
554#define CHECK(str) \
555 do \
556 { \
557 RTPrintf("%s rc=%Vrc\n", str, rc); \
558 if (VBOX_FAILURE(rc)) \
559 { \
560 VDCloseAll(pVD); \
561 return rc; \
562 } \
563 } while (0)
564
565 /* Create error interface. */
566 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
567 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
568 VDIErrorCallbacks.pfnError = tstVDError;
569
570 rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
571 NULL, NULL);
572 AssertRC(rc);
573
574
575 rc = VDCreate(&VDIError, &pVD);
576 CHECK("VDCreate()");
577
578 RTFILE File;
579 rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ);
580 if (VBOX_SUCCESS(rc))
581 {
582 RTFileClose(File);
583 RTFileDelete(pszFilename);
584 }
585
586 rc = VDCreateBase(pVD, pszBackend, pszFilename,
587 VD_IMAGE_TYPE_NORMAL, u64DiskSize,
588 VD_IMAGE_FLAGS_NONE, "Test image",
589 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
590 NULL, NULL);
591 CHECK("VDCreateBase()");
592
593 int nSegments = 100;
594 /* Allocate one extra element for a sentinel. */
595 PSEGMENT paSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
596
597 void *pvBuf = RTMemAlloc(_1M);
598
599 RNDCTX ctx;
600 initializeRandomGenerator(&ctx, u32Seed);
601 generateRandomSegments(&ctx, paSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u);
602 /*for (PSEGMENT pSegment = paSegments; pSegment->u32Length; pSegment++)
603 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
604
605 writeSegmentsToDisk(pVD, pvBuf, paSegments);
606
607 VDCloseAll(pVD);
608
609 rc = VDOpen(pVD, pszBackend, pszFilename, VD_OPEN_FLAGS_NORMAL);
610 CHECK("VDOpen()");
611 rc = readAndCompareSegments(pVD, pvBuf, paSegments);
612 CHECK("readAndCompareSegments()");
613
614 RTMemFree(paSegments);
615
616 VDCloseAll(pVD);
617#undef CHECK
618 return 0;
619}
620
621
622int main(int argc, char *argv[])
623{
624 int rc;
625
626 uint32_t u32Seed = 0; // Means choose random
627
628 if (argc > 1)
629 if (sscanf(argv[1], "%x", &u32Seed) != 1)
630 {
631 RTPrintf("ERROR: Invalid parameter %s. Valid usage is %s <32-bit seed>.\n",
632 argv[1], argv[0]);
633 return 1;
634 }
635
636 RTR3Init();
637 RTPrintf("tstVD: TESTING...\n");
638
639 /*
640 * Clean up potential leftovers from previous unsuccessful runs.
641 */
642 RTFileDelete("tmpVDCreate.vdi");
643 RTFileDelete("tmpVDCreate.vmdk");
644 RTFileDelete("tmpVDCreate.vhd");
645 RTFileDelete("tmpVDBase.vdi");
646 RTFileDelete("tmpVDDiff.vdi");
647 RTFileDelete("tmpVDBase.vmdk");
648 RTFileDelete("tmpVDDiff.vmdk");
649 RTFileDelete("tmpVDBase.vhd");
650 RTFileDelete("tmpVDDiff.vhd");
651#if 1
652 rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
653 VD_IMAGE_TYPE_NORMAL, VD_IMAGE_FLAGS_NONE,
654 true);
655 if (VBOX_FAILURE(rc))
656 {
657 RTPrintf("tstVD: dynamic VDI create test failed! rc=%Vrc\n", rc);
658 g_cErrors++;
659 }
660 rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
661 VD_IMAGE_TYPE_FIXED, VD_IMAGE_FLAGS_NONE,
662 true);
663 if (VBOX_FAILURE(rc))
664 {
665 RTPrintf("tstVD: fixed VDI create test failed! rc=%Vrc\n", rc);
666 g_cErrors++;
667 }
668 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
669 VD_IMAGE_TYPE_NORMAL, VD_IMAGE_FLAGS_NONE,
670 true);
671 if (VBOX_FAILURE(rc))
672 {
673 RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Vrc\n", rc);
674 g_cErrors++;
675 }
676 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
677 VD_IMAGE_TYPE_NORMAL, VD_VMDK_IMAGE_FLAGS_SPLIT_2G,
678 true);
679 if (VBOX_FAILURE(rc))
680 {
681 RTPrintf("tstVD: dynamic split VMDK create test failed! rc=%Vrc\n", rc);
682 g_cErrors++;
683 }
684 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
685 VD_IMAGE_TYPE_FIXED, VD_IMAGE_FLAGS_NONE,
686 true);
687 if (VBOX_FAILURE(rc))
688 {
689 RTPrintf("tstVD: fixed VMDK create test failed! rc=%Vrc\n", rc);
690 g_cErrors++;
691 }
692 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
693 VD_IMAGE_TYPE_FIXED, VD_VMDK_IMAGE_FLAGS_SPLIT_2G,
694 true);
695 if (VBOX_FAILURE(rc))
696 {
697 RTPrintf("tstVD: fixed split VMDK create test failed! rc=%Vrc\n", rc);
698 g_cErrors++;
699 }
700 rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
701 VD_IMAGE_TYPE_NORMAL, VD_IMAGE_FLAGS_NONE,
702 true);
703 if (VBOX_FAILURE(rc))
704 {
705 RTPrintf("tstVD: dynamic VHD create test failed! rc=%Vrc\n", rc);
706 g_cErrors++;
707 }
708 rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
709 VD_IMAGE_TYPE_FIXED, VD_IMAGE_FLAGS_NONE,
710 true);
711 if (VBOX_FAILURE(rc))
712 {
713 RTPrintf("tstVD: fixed VHD create test failed! rc=%Vrc\n", rc);
714 g_cErrors++;
715 }
716
717 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
718 if (VBOX_FAILURE(rc))
719 {
720 RTPrintf("tstVD: VDI test failed (new image)! rc=%Vrc\n", rc);
721 g_cErrors++;
722 }
723 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
724 if (VBOX_FAILURE(rc))
725 {
726 RTPrintf("tstVD: VDI test failed (existing image)! rc=%Vrc\n", rc);
727 g_cErrors++;
728 }
729 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
730 if (VBOX_FAILURE(rc))
731 {
732 RTPrintf("tstVD: VMDK test failed (new image)! rc=%Vrc\n", rc);
733 g_cErrors++;
734 }
735 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
736 if (VBOX_FAILURE(rc))
737 {
738 RTPrintf("tstVD: VMDK test failed (existing image)! rc=%Vrc\n", rc);
739 g_cErrors++;
740 }
741#endif
742
743 rc = tstVDCreateWriteOpenRead("VHD", "tmpVDCreate.vhd", u32Seed);
744 if (VBOX_FAILURE(rc))
745 {
746 RTPrintf("tstVD: VHD test failed (creating image)! rc=%Vrc\n", rc);
747 g_cErrors++;
748 }
749
750 rc = tstVDOpenCreateWriteMerge("VHD", "tmpVDBase.vhd", "tmpVDDiff.vhd", u32Seed);
751 if (VBOX_FAILURE(rc))
752 {
753 RTPrintf("tstVD: VHD test failed (existing image)! rc=%Vrc\n", rc);
754 g_cErrors++;
755 }
756
757 /*
758 * Clean up any leftovers.
759 */
760 RTFileDelete("tmpVDCreate.vdi");
761 RTFileDelete("tmpVDCreate.vmdk");
762 RTFileDelete("tmpVDCreate.vhd");
763 RTFileDelete("tmpVDBase.vdi");
764 RTFileDelete("tmpVDDiff.vdi");
765 RTFileDelete("tmpVDBase.vmdk");
766 RTFileDelete("tmpVDDiff.vmdk");
767 RTFileDelete("tmpVDBase.vhd");
768 RTFileDelete("tmpVDDiff.vhd");
769
770 /*
771 * Summary
772 */
773 if (!g_cErrors)
774 RTPrintf("tstVD: SUCCESS\n");
775 else
776 RTPrintf("tstVD: FAILURE - %d errors\n", g_cErrors);
777
778 return !!g_cErrors;
779}
780
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