VirtualBox

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

Last change on this file since 33000 was 32536, checked in by vboxsync, 14 years ago

Storage/VBoxHDD: replace custom open flags with regular IPRT file open flags, introduce user-providable filesystem access interface, eliminate dependency on PGM geometry structure, change pvBuffer/cbBuffer parameter ordering to the usual conventions, eliminate the remains of the old I/O code, make more plugin methods optional to reduce redundancy, lots of cleanups

Storage/DrvVD+testcases,Main/Medium+Frontends: adapt to VBoxHDD changes, logging fixes

Storage/VDI+VMDK+DMG+Raw+VHD+Parallels+VCI: made as similar to each other as possible, added inline VFS wrappers to improve readability, full VFS support, VDI files are now 4K aligned, eliminate the remains of the old I/O code, various more or less severe bugfixes, code sort

Storage/iSCSI: support disks bigger than 2T, streamline the code to be more similar to the file-based backends, memory leak fix, error code usage like file-based backends, code sort

log+err: added new error codes/log groups and eliminated unused old ones

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.4 KB
Line 
1/* $Id: tstVD.cpp 32536 2010-09-15 18:25: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/VBoxHDD.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, &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, &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 VDGEOMETRY PCHS = { 0, 0, 0 };
508 VDGEOMETRY LCHS = { 0, 0, 0 };
509 uint64_t u64DiskSize = 1000 * _1M;
510 uint32_t u32SectorSize = 512;
511 PVDINTERFACE pVDIfs = NULL;
512 VDINTERFACE VDIError;
513 VDINTERFACEERROR VDIErrorCallbacks;
514
515#define CHECK(str) \
516 do \
517 { \
518 RTPrintf("%s rc=%Rrc\n", str, rc); \
519 if (RT_FAILURE(rc)) \
520 { \
521 if (pvBuf) \
522 RTMemFree(pvBuf); \
523 VDDestroy(pVD); \
524 return rc; \
525 } \
526 } while (0)
527
528 void *pvBuf = RTMemAlloc(_1M);
529
530 /* Create error interface. */
531 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
532 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
533 VDIErrorCallbacks.pfnError = tstVDError;
534 VDIErrorCallbacks.pfnMessage = tstVDMessage;
535
536 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
537 NULL, &pVDIfs);
538 AssertRC(rc);
539
540
541 rc = VDCreate(&VDIError, &pVD);
542 CHECK("VDCreate()");
543
544 RTFILE File;
545 rc = RTFileOpen(&File, pszBaseFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
546 if (RT_SUCCESS(rc))
547 {
548 RTFileClose(File);
549 rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
550 pszBaseFilename, &pszFormat);
551 RTPrintf("VDGetFormat() pszFormat=%s rc=%Rrc\n", pszFormat, rc);
552 if (RT_SUCCESS(rc) && strcmp(pszFormat, pszBackend))
553 {
554 rc = VERR_GENERAL_FAILURE;
555 RTPrintf("VDGetFormat() returned incorrect backend name\n");
556 }
557 RTStrFree(pszFormat);
558 CHECK("VDGetFormat()");
559
560 rc = VDOpen(pVD, pszBackend, pszBaseFilename, VD_OPEN_FLAGS_NORMAL,
561 NULL);
562 CHECK("VDOpen()");
563 }
564 else
565 {
566 rc = VDCreateBase(pVD, pszBackend, pszBaseFilename, u64DiskSize,
567 VD_IMAGE_FLAGS_NONE, "Test image",
568 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
569 NULL, NULL);
570 CHECK("VDCreateBase()");
571 }
572
573 int nSegments = 100;
574 /* Allocate one extra element for a sentinel. */
575 PSEGMENT paBaseSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
576 PSEGMENT paDiffSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
577 PSEGMENT paMergeSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1) * 3);
578
579 RNDCTX ctx;
580 initializeRandomGenerator(&ctx, u32Seed);
581 generateRandomSegments(&ctx, paBaseSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u);
582 generateRandomSegments(&ctx, paDiffSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 128u, 255u);
583
584 /*PSEGMENT pSegment;
585 RTPrintf("Base segments:\n");
586 for (pSegment = paBaseSegments; pSegment->u32Length; pSegment++)
587 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
588 writeSegmentsToDisk(pVD, pvBuf, paBaseSegments);
589
590 rc = VDCreateDiff(pVD, pszBackend, pszDiffFilename,
591 VD_IMAGE_FLAGS_NONE, "Test diff image", NULL, NULL,
592 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
593 CHECK("VDCreateDiff()");
594
595 /*RTPrintf("\nDiff segments:\n");
596 for (pSegment = paDiffSegments; pSegment->u32Length; pSegment++)
597 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
598 writeSegmentsToDisk(pVD, pvBuf, paDiffSegments);
599
600 VDDumpImages(pVD);
601
602 RTPrintf("Merging diff into base..\n");
603 rc = VDMerge(pVD, VD_LAST_IMAGE, 0, NULL);
604 CHECK("VDMerge()");
605
606 mergeSegments(paBaseSegments, paDiffSegments, paMergeSegments, _1M);
607 /*RTPrintf("\nMerged segments:\n");
608 for (pSegment = paMergeSegments; pSegment->u32Length; pSegment++)
609 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
610 rc = readAndCompareSegments(pVD, pvBuf, paMergeSegments);
611 CHECK("readAndCompareSegments()");
612
613 RTMemFree(paMergeSegments);
614 RTMemFree(paDiffSegments);
615 RTMemFree(paBaseSegments);
616
617 VDDumpImages(pVD);
618
619 VDDestroy(pVD);
620 if (pvBuf)
621 RTMemFree(pvBuf);
622#undef CHECK
623 return 0;
624}
625
626static int tstVDCreateWriteOpenRead(const char *pszBackend,
627 const char *pszFilename,
628 uint32_t u32Seed)
629{
630 int rc;
631 PVBOXHDD pVD = NULL;
632 VDGEOMETRY PCHS = { 0, 0, 0 };
633 VDGEOMETRY LCHS = { 0, 0, 0 };
634 uint64_t u64DiskSize = 1000 * _1M;
635 uint32_t u32SectorSize = 512;
636 PVDINTERFACE pVDIfs = NULL;
637 VDINTERFACE VDIError;
638 VDINTERFACEERROR VDIErrorCallbacks;
639
640#define CHECK(str) \
641 do \
642 { \
643 RTPrintf("%s rc=%Rrc\n", str, rc); \
644 if (RT_FAILURE(rc)) \
645 { \
646 if (pvBuf) \
647 RTMemFree(pvBuf); \
648 VDDestroy(pVD); \
649 return rc; \
650 } \
651 } while (0)
652
653 void *pvBuf = RTMemAlloc(_1M);
654
655 /* Create error interface. */
656 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
657 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
658 VDIErrorCallbacks.pfnError = tstVDError;
659 VDIErrorCallbacks.pfnMessage = tstVDMessage;
660
661 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
662 NULL, &pVDIfs);
663 AssertRC(rc);
664
665
666 rc = VDCreate(&VDIError, &pVD);
667 CHECK("VDCreate()");
668
669 RTFILE File;
670 rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
671 if (RT_SUCCESS(rc))
672 {
673 RTFileClose(File);
674 RTFileDelete(pszFilename);
675 }
676
677 rc = VDCreateBase(pVD, pszBackend, pszFilename, u64DiskSize,
678 VD_IMAGE_FLAGS_NONE, "Test image",
679 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
680 NULL, NULL);
681 CHECK("VDCreateBase()");
682
683 int nSegments = 100;
684 /* Allocate one extra element for a sentinel. */
685 PSEGMENT paSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1));
686
687 RNDCTX ctx;
688 initializeRandomGenerator(&ctx, u32Seed);
689 generateRandomSegments(&ctx, paSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u);
690 /*for (PSEGMENT pSegment = paSegments; pSegment->u32Length; pSegment++)
691 RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
692
693 writeSegmentsToDisk(pVD, pvBuf, paSegments);
694
695 VDCloseAll(pVD);
696
697 rc = VDOpen(pVD, pszBackend, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
698 CHECK("VDOpen()");
699 rc = readAndCompareSegments(pVD, pvBuf, paSegments);
700 CHECK("readAndCompareSegments()");
701
702 RTMemFree(paSegments);
703
704 VDDestroy(pVD);
705 if (pvBuf)
706 RTMemFree(pvBuf);
707#undef CHECK
708 return 0;
709}
710
711static int tstVmdkRename(const char *src, const char *dst)
712{
713 int rc;
714 PVBOXHDD pVD = NULL;
715 PVDINTERFACE pVDIfs = NULL;
716 VDINTERFACE VDIError;
717 VDINTERFACEERROR VDIErrorCallbacks;
718
719#define CHECK(str) \
720 do \
721 { \
722 RTPrintf("%s rc=%Rrc\n", str, rc); \
723 if (RT_FAILURE(rc)) \
724 { \
725 VDDestroy(pVD); \
726 return rc; \
727 } \
728 } while (0)
729
730 /* Create error interface. */
731 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
732 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
733 VDIErrorCallbacks.pfnError = tstVDError;
734 VDIErrorCallbacks.pfnMessage = tstVDMessage;
735
736 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
737 NULL, &pVDIfs);
738 AssertRC(rc);
739
740 rc = VDCreate(&VDIError, &pVD);
741 CHECK("VDCreate()");
742
743 rc = VDOpen(pVD, "VMDK", src, VD_OPEN_FLAGS_NORMAL, NULL);
744 CHECK("VDOpen()");
745 rc = VDCopy(pVD, 0, pVD, "VMDK", dst, true, 0, VD_IMAGE_FLAGS_NONE, NULL, NULL, NULL, NULL);
746 CHECK("VDCopy()");
747
748 VDDestroy(pVD);
749#undef CHECK
750 return 0;
751}
752
753static int tstVmdkCreateRenameOpen(const char *src, const char *dst,
754 uint64_t cbSize, unsigned uFlags)
755{
756 int rc = tstVDCreateDelete("VMDK", src, cbSize, uFlags, false);
757 if (RT_FAILURE(rc))
758 return rc;
759
760 rc = tstVmdkRename(src, dst);
761 if (RT_FAILURE(rc))
762 return rc;
763
764 PVBOXHDD pVD = NULL;
765 PVDINTERFACE pVDIfs = NULL;
766 VDINTERFACE VDIError;
767 VDINTERFACEERROR VDIErrorCallbacks;
768
769#define CHECK(str) \
770 do \
771 { \
772 RTPrintf("%s rc=%Rrc\n", str, rc); \
773 if (RT_FAILURE(rc)) \
774 { \
775 VDCloseAll(pVD); \
776 return rc; \
777 } \
778 } while (0)
779
780 /* Create error interface. */
781 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
782 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
783 VDIErrorCallbacks.pfnError = tstVDError;
784 VDIErrorCallbacks.pfnMessage = tstVDMessage;
785
786 rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
787 NULL, &pVDIfs);
788 AssertRC(rc);
789
790 rc = VDCreate(&VDIError, &pVD);
791 CHECK("VDCreate()");
792
793 rc = VDOpen(pVD, "VMDK", dst, VD_OPEN_FLAGS_NORMAL, NULL);
794 CHECK("VDOpen()");
795
796 VDClose(pVD, true);
797 CHECK("VDClose()");
798 VDDestroy(pVD);
799#undef CHECK
800 return rc;
801}
802
803#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
804#define DST_PATH "tmp\\tmpVDRename.vmdk"
805#else
806#define DST_PATH "tmp/tmpVDRename.vmdk"
807#endif
808
809static void tstVmdk()
810{
811 int rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", "tmpVDRename.vmdk", _4G,
812 VD_IMAGE_FLAGS_NONE);
813 if (RT_FAILURE(rc))
814 {
815 RTPrintf("tstVD: VMDK rename (single extent, embedded descriptor, same dir) test failed! rc=%Rrc\n", rc);
816 g_cErrors++;
817 }
818 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", "tmpVDRename.vmdk", _4G,
819 VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
820 if (RT_FAILURE(rc))
821 {
822 RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, same dir) test failed! rc=%Rrc\n", rc);
823 g_cErrors++;
824 }
825 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
826 VD_IMAGE_FLAGS_NONE);
827 if (RT_FAILURE(rc))
828 {
829 RTPrintf("tstVD: VMDK rename (single extent, embedded descriptor, another dir) test failed! rc=%Rrc\n", rc);
830 g_cErrors++;
831 }
832 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
833 VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
834 if (RT_FAILURE(rc))
835 {
836 RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, another dir) test failed! rc=%Rrc\n", rc);
837 g_cErrors++;
838 }
839
840 RTFILE File;
841 rc = RTFileOpen(&File, DST_PATH, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE);
842 if (RT_SUCCESS(rc))
843 RTFileClose(File);
844
845 rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
846 VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
847 if (RT_SUCCESS(rc))
848 {
849 RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, another dir, already exists) test failed!\n");
850 g_cErrors++;
851 }
852 RTFileDelete(DST_PATH);
853 RTFileDelete("tmpVDCreate.vmdk");
854 RTFileDelete("tmpVDCreate-s001.vmdk");
855 RTFileDelete("tmpVDCreate-s002.vmdk");
856 RTFileDelete("tmpVDCreate-s003.vmdk");
857}
858
859int main(int argc, char *argv[])
860{
861 RTR3Init();
862 int rc;
863
864 uint32_t u32Seed = 0; // Means choose random
865
866 if (argc > 1)
867 if (sscanf(argv[1], "%x", &u32Seed) != 1)
868 {
869 RTPrintf("ERROR: Invalid parameter %s. Valid usage is %s <32-bit seed>.\n",
870 argv[1], argv[0]);
871 return 1;
872 }
873
874 RTPrintf("tstVD: TESTING...\n");
875
876 /*
877 * Clean up potential leftovers from previous unsuccessful runs.
878 */
879 RTFileDelete("tmpVDCreate.vdi");
880 RTFileDelete("tmpVDCreate.vmdk");
881 RTFileDelete("tmpVDCreate.vhd");
882 RTFileDelete("tmpVDBase.vdi");
883 RTFileDelete("tmpVDDiff.vdi");
884 RTFileDelete("tmpVDBase.vmdk");
885 RTFileDelete("tmpVDDiff.vmdk");
886 RTFileDelete("tmpVDBase.vhd");
887 RTFileDelete("tmpVDDiff.vhd");
888 RTFileDelete("tmpVDCreate-s001.vmdk");
889 RTFileDelete("tmpVDCreate-s002.vmdk");
890 RTFileDelete("tmpVDCreate-s003.vmdk");
891 RTFileDelete("tmpVDRename.vmdk");
892 RTFileDelete("tmpVDRename-s001.vmdk");
893 RTFileDelete("tmpVDRename-s002.vmdk");
894 RTFileDelete("tmpVDRename-s003.vmdk");
895 RTFileDelete("tmp/tmpVDRename.vmdk");
896 RTFileDelete("tmp/tmpVDRename-s001.vmdk");
897 RTFileDelete("tmp/tmpVDRename-s002.vmdk");
898 RTFileDelete("tmp/tmpVDRename-s003.vmdk");
899
900 if (!RTDirExists("tmp"))
901 {
902 rc = RTDirCreate("tmp", RTFS_UNIX_IRWXU);
903 if (RT_FAILURE(rc))
904 {
905 RTPrintf("tstVD: Failed to create 'tmp' directory! rc=%Rrc\n", rc);
906 g_cErrors++;
907 }
908 }
909
910#ifdef VMDK_TEST
911 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
912 VD_IMAGE_FLAGS_NONE, true);
913 if (RT_FAILURE(rc))
914 {
915 RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
916 g_cErrors++;
917 }
918 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
919 VD_IMAGE_FLAGS_NONE, false);
920 if (RT_FAILURE(rc))
921 {
922 RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
923 g_cErrors++;
924 }
925 rc = tstVDOpenDelete("VMDK", "tmpVDCreate.vmdk");
926 if (RT_FAILURE(rc))
927 {
928 RTPrintf("tstVD: VMDK delete test failed! rc=%Rrc\n", rc);
929 g_cErrors++;
930 }
931
932 tstVmdk();
933#endif /* VMDK_TEST */
934#ifdef VDI_TEST
935 rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
936 VD_IMAGE_FLAGS_NONE, true);
937 if (RT_FAILURE(rc))
938 {
939 RTPrintf("tstVD: dynamic VDI create test failed! rc=%Rrc\n", rc);
940 g_cErrors++;
941 }
942 rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
943 VD_IMAGE_FLAGS_NONE, true);
944 if (RT_FAILURE(rc))
945 {
946 RTPrintf("tstVD: fixed VDI create test failed! rc=%Rrc\n", rc);
947 g_cErrors++;
948 }
949#endif /* VDI_TEST */
950#ifdef VMDK_TEST
951 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
952 VD_IMAGE_FLAGS_NONE, true);
953 if (RT_FAILURE(rc))
954 {
955 RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
956 g_cErrors++;
957 }
958 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
959 VD_VMDK_IMAGE_FLAGS_SPLIT_2G, true);
960 if (RT_FAILURE(rc))
961 {
962 RTPrintf("tstVD: dynamic split VMDK create test failed! rc=%Rrc\n", rc);
963 g_cErrors++;
964 }
965 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
966 VD_IMAGE_FLAGS_FIXED, true);
967 if (RT_FAILURE(rc))
968 {
969 RTPrintf("tstVD: fixed VMDK create test failed! rc=%Rrc\n", rc);
970 g_cErrors++;
971 }
972 rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
973 VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_SPLIT_2G,
974 true);
975 if (RT_FAILURE(rc))
976 {
977 RTPrintf("tstVD: fixed split VMDK create test failed! rc=%Rrc\n", rc);
978 g_cErrors++;
979 }
980#endif /* VMDK_TEST */
981#ifdef VHD_TEST
982 rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
983 VD_IMAGE_FLAGS_NONE, true);
984 if (RT_FAILURE(rc))
985 {
986 RTPrintf("tstVD: dynamic VHD create test failed! rc=%Rrc\n", rc);
987 g_cErrors++;
988 }
989 rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
990 VD_IMAGE_FLAGS_FIXED, true);
991 if (RT_FAILURE(rc))
992 {
993 RTPrintf("tstVD: fixed VHD create test failed! rc=%Rrc\n", rc);
994 g_cErrors++;
995 }
996#endif /* VHD_TEST */
997#ifdef VDI_TEST
998 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
999 if (RT_FAILURE(rc))
1000 {
1001 RTPrintf("tstVD: VDI test failed (new image)! rc=%Rrc\n", rc);
1002 g_cErrors++;
1003 }
1004 rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
1005 if (RT_FAILURE(rc))
1006 {
1007 RTPrintf("tstVD: VDI test failed (existing image)! rc=%Rrc\n", rc);
1008 g_cErrors++;
1009 }
1010#endif /* VDI_TEST */
1011#ifdef VMDK_TEST
1012 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
1013 if (RT_FAILURE(rc))
1014 {
1015 RTPrintf("tstVD: VMDK test failed (new image)! rc=%Rrc\n", rc);
1016 g_cErrors++;
1017 }
1018 rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
1019 if (RT_FAILURE(rc))
1020 {
1021 RTPrintf("tstVD: VMDK test failed (existing image)! rc=%Rrc\n", rc);
1022 g_cErrors++;
1023 }
1024#endif /* VMDK_TEST */
1025#ifdef VHD_TEST
1026 rc = tstVDCreateWriteOpenRead("VHD", "tmpVDCreate.vhd", u32Seed);
1027 if (RT_FAILURE(rc))
1028 {
1029 RTPrintf("tstVD: VHD test failed (creating image)! rc=%Rrc\n", rc);
1030 g_cErrors++;
1031 }
1032
1033 rc = tstVDOpenCreateWriteMerge("VHD", "tmpVDBase.vhd", "tmpVDDiff.vhd", u32Seed);
1034 if (RT_FAILURE(rc))
1035 {
1036 RTPrintf("tstVD: VHD test failed (existing image)! rc=%Rrc\n", rc);
1037 g_cErrors++;
1038 }
1039#endif /* VHD_TEST */
1040
1041 /*
1042 * Clean up any leftovers.
1043 */
1044 RTFileDelete("tmpVDCreate.vdi");
1045 RTFileDelete("tmpVDCreate.vmdk");
1046 RTFileDelete("tmpVDCreate.vhd");
1047 RTFileDelete("tmpVDBase.vdi");
1048 RTFileDelete("tmpVDDiff.vdi");
1049 RTFileDelete("tmpVDBase.vmdk");
1050 RTFileDelete("tmpVDDiff.vmdk");
1051 RTFileDelete("tmpVDBase.vhd");
1052 RTFileDelete("tmpVDDiff.vhd");
1053 RTFileDelete("tmpVDCreate-s001.vmdk");
1054 RTFileDelete("tmpVDCreate-s002.vmdk");
1055 RTFileDelete("tmpVDCreate-s003.vmdk");
1056 RTFileDelete("tmpVDRename.vmdk");
1057 RTFileDelete("tmpVDRename-s001.vmdk");
1058 RTFileDelete("tmpVDRename-s002.vmdk");
1059 RTFileDelete("tmpVDRename-s003.vmdk");
1060
1061 rc = VDShutdown();
1062 if (RT_FAILURE(rc))
1063 {
1064 RTPrintf("tstVD: unloading backends failed! rc=%Rrc\n", rc);
1065 g_cErrors++;
1066 }
1067 /*
1068 * Summary
1069 */
1070 if (!g_cErrors)
1071 RTPrintf("tstVD: SUCCESS\n");
1072 else
1073 RTPrintf("tstVD: FAILURE - %d errors\n", g_cErrors);
1074
1075 return !!g_cErrors;
1076}
1077
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use