VirtualBox

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

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

IPRT/*: add _NO_SYMLINKS flags to certain functions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.6 KB
Line 
1/* $Id: tstVD.cpp 39612 2011-12-14 14:19:55Z 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 RTR3InitExe(argc, &argv, 0);
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, 0);
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