[29250] | 1 | /* $Id: tstVD.cpp 32536 2010-09-15 18:25:32Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
| 3 | * Simple VBox HDD container test utility.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[32536] | 7 | * Copyright (C) 2006-2010 Oracle Corporation
|
---|
[1] | 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
|
---|
[5999] | 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.
|
---|
[1] | 16 | */
|
---|
| 17 |
|
---|
[29250] | 18 | /*******************************************************************************
|
---|
| 19 | * Header Files *
|
---|
| 20 | *******************************************************************************/
|
---|
[16873] | 21 | #include <VBox/VBoxHDD.h>
|
---|
[1] | 22 | #include <VBox/err.h>
|
---|
[14817] | 23 | #include <VBox/log.h>
|
---|
[29250] | 24 | #include <iprt/asm-amd64-x86.h>
|
---|
[13268] | 25 | #include <iprt/dir.h>
|
---|
[1] | 26 | #include <iprt/string.h>
|
---|
[728] | 27 | #include <iprt/stream.h>
|
---|
[7895] | 28 | #include <iprt/file.h>
|
---|
[728] | 29 | #include <iprt/mem.h>
|
---|
[7895] | 30 | #include <iprt/initterm.h>
|
---|
[9262] | 31 | #include <iprt/rand.h>
|
---|
| 32 | #include "stdio.h"
|
---|
| 33 | #include "stdlib.h"
|
---|
[1] | 34 |
|
---|
[13295] | 35 | #define VHD_TEST
|
---|
| 36 | #define VDI_TEST
|
---|
| 37 | #define VMDK_TEST
|
---|
| 38 |
|
---|
[7895] | 39 | /*******************************************************************************
|
---|
| 40 | * Global Variables *
|
---|
| 41 | *******************************************************************************/
|
---|
| 42 | /** The error count. */
|
---|
| 43 | unsigned g_cErrors = 0;
|
---|
[1] | 44 |
|
---|
[7895] | 45 |
|
---|
| 46 | static void tstVDError(void *pvUser, int rc, RT_SRC_POS_DECL,
|
---|
| 47 | const char *pszFormat, va_list va)
|
---|
[1] | 48 | {
|
---|
[7895] | 49 | g_cErrors++;
|
---|
[13837] | 50 | RTPrintf("tstVD: Error %Rrc at %s:%u (%s): ", rc, RT_SRC_POS_ARGS);
|
---|
[7895] | 51 | RTPrintfV(pszFormat, va);
|
---|
| 52 | RTPrintf("\n");
|
---|
| 53 | }
|
---|
[1] | 54 |
|
---|
[32536] | 55 | static int tstVDMessage(void *pvUser, const char *pszFormat, va_list va)
|
---|
[26988] | 56 | {
|
---|
| 57 | RTPrintf("tstVD: ");
|
---|
| 58 | RTPrintfV(pszFormat, va);
|
---|
| 59 | return VINF_SUCCESS;
|
---|
| 60 | }
|
---|
| 61 |
|
---|
[8248] | 62 | static int tstVDCreateDelete(const char *pszBackend, const char *pszFilename,
|
---|
[17970] | 63 | uint64_t cbSize, unsigned uFlags, bool fDelete)
|
---|
[8248] | 64 | {
|
---|
| 65 | int rc;
|
---|
| 66 | PVBOXHDD pVD = NULL;
|
---|
[32536] | 67 | VDGEOMETRY PCHS = { 0, 0, 0 };
|
---|
| 68 | VDGEOMETRY LCHS = { 0, 0, 0 };
|
---|
[11435] | 69 | PVDINTERFACE pVDIfs = NULL;
|
---|
[10715] | 70 | VDINTERFACE VDIError;
|
---|
| 71 | VDINTERFACEERROR VDIErrorCallbacks;
|
---|
[8248] | 72 |
|
---|
| 73 | #define CHECK(str) \
|
---|
| 74 | do \
|
---|
| 75 | { \
|
---|
[13837] | 76 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
[13835] | 77 | if (RT_FAILURE(rc)) \
|
---|
[8248] | 78 | { \
|
---|
[13295] | 79 | VDDestroy(pVD); \
|
---|
[8248] | 80 | return rc; \
|
---|
| 81 | } \
|
---|
| 82 | } while (0)
|
---|
| 83 |
|
---|
[10715] | 84 | /* Create error interface. */
|
---|
| 85 | VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
|
---|
| 86 | VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
|
---|
| 87 | VDIErrorCallbacks.pfnError = tstVDError;
|
---|
[26988] | 88 | VDIErrorCallbacks.pfnMessage = tstVDMessage;
|
---|
[10715] | 89 |
|
---|
[11435] | 90 | rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
|
---|
| 91 | NULL, &pVDIfs);
|
---|
[10715] | 92 | AssertRC(rc);
|
---|
| 93 |
|
---|
| 94 | rc = VDCreate(&VDIError, &pVD);
|
---|
[8248] | 95 | CHECK("VDCreate()");
|
---|
| 96 |
|
---|
[17970] | 97 | rc = VDCreateBase(pVD, pszBackend, pszFilename, cbSize,
|
---|
[11353] | 98 | uFlags, "Test image", &PCHS, &LCHS, NULL,
|
---|
| 99 | VD_OPEN_FLAGS_NORMAL, NULL, NULL);
|
---|
[8248] | 100 | CHECK("VDCreateBase()");
|
---|
| 101 |
|
---|
| 102 | VDDumpImages(pVD);
|
---|
| 103 |
|
---|
| 104 | VDClose(pVD, fDelete);
|
---|
[13268] | 105 | if (fDelete)
|
---|
| 106 | {
|
---|
| 107 | RTFILE File;
|
---|
[23973] | 108 | rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
|
---|
[13835] | 109 | if (RT_SUCCESS(rc))
|
---|
[13268] | 110 | {
|
---|
| 111 | RTFileClose(File);
|
---|
| 112 | return VERR_INTERNAL_ERROR;
|
---|
| 113 | }
|
---|
| 114 | }
|
---|
| 115 |
|
---|
[13295] | 116 | VDDestroy(pVD);
|
---|
[8248] | 117 | #undef CHECK
|
---|
| 118 | return 0;
|
---|
| 119 | }
|
---|
| 120 |
|
---|
[13268] | 121 | static int tstVDOpenDelete(const char *pszBackend, const char *pszFilename)
|
---|
| 122 | {
|
---|
| 123 | int rc;
|
---|
| 124 | PVBOXHDD pVD = NULL;
|
---|
[32536] | 125 | VDGEOMETRY PCHS = { 0, 0, 0 };
|
---|
| 126 | VDGEOMETRY LCHS = { 0, 0, 0 };
|
---|
[13268] | 127 | PVDINTERFACE pVDIfs = NULL;
|
---|
| 128 | VDINTERFACE VDIError;
|
---|
| 129 | VDINTERFACEERROR VDIErrorCallbacks;
|
---|
[7895] | 130 |
|
---|
[13268] | 131 | #define CHECK(str) \
|
---|
| 132 | do \
|
---|
| 133 | { \
|
---|
[13837] | 134 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
[13835] | 135 | if (RT_FAILURE(rc)) \
|
---|
[13268] | 136 | { \
|
---|
[13295] | 137 | VDDestroy(pVD); \
|
---|
[13268] | 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;
|
---|
[26988] | 146 | VDIErrorCallbacks.pfnMessage = tstVDMessage;
|
---|
[13268] | 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;
|
---|
[23973] | 162 | rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
|
---|
[13835] | 163 | if (RT_SUCCESS(rc))
|
---|
[13268] | 164 | {
|
---|
| 165 | RTFileClose(File);
|
---|
| 166 | return VERR_INTERNAL_ERROR;
|
---|
| 167 | }
|
---|
| 168 |
|
---|
[13295] | 169 | VDDestroy(pVD);
|
---|
[13268] | 170 | #undef CHECK
|
---|
| 171 | return 0;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 |
|
---|
[9262] | 175 | #undef RTDECL
|
---|
| 176 | #define RTDECL(x) static x
|
---|
[728] | 177 |
|
---|
[9262] | 178 | /* Start of IPRT code */
|
---|
| 179 |
|
---|
| 180 | /**
|
---|
[11353] | 181 | * The following code is based on the work of George Marsaglia
|
---|
| 182 | * taken from
|
---|
[9262] | 183 | * http://groups.google.ws/group/comp.sys.sun.admin/msg/7c667186f6cbf354
|
---|
[11353] | 184 | * and
|
---|
| 185 | * http://groups.google.ws/group/comp.lang.c/msg/0e170777c6e79e8d
|
---|
[9262] | 186 | */
|
---|
| 187 |
|
---|
[11353] | 188 | /*
|
---|
| 189 | A C version of a very very good 64-bit RNG is given below.
|
---|
| 190 | You should be able to adapt it to your particular needs.
|
---|
[9262] | 191 |
|
---|
[11353] | 192 | It is based on the complimentary-multiple-with-carry
|
---|
| 193 | sequence
|
---|
| 194 | x(n)=a*x(n-4)+carry mod 2^64-1,
|
---|
| 195 | which works as follows:
|
---|
| 196 | Assume a certain multiplier 'a' and a base 'b'.
|
---|
| 197 | Given a current x value and a current carry 'c',
|
---|
| 198 | form: t=a*x+c
|
---|
| 199 | Then the new carry is c=floor(t/b)
|
---|
| 200 | and the new x value is x = b-1-(t mod b).
|
---|
[9262] | 201 |
|
---|
| 202 |
|
---|
[11353] | 203 | Ordinarily, for 32-bit mwc or cmwc sequences, the
|
---|
| 204 | value t=a*x+c can be formed in 64 bits, then the new c
|
---|
| 205 | is the top and the new x the bottom 32 bits (with a little
|
---|
| 206 | fiddling when b=2^32-1 and cmwc rather than mwc.)
|
---|
[9262] | 207 |
|
---|
| 208 |
|
---|
[11353] | 209 | To generate 64-bit x's, it is difficult to form
|
---|
| 210 | t=a*x+c in 128 bits then get the new c and new x
|
---|
[14303] | 211 | from the top and bottom halves.
|
---|
[11353] | 212 | But if 'a' has a special form, for example,
|
---|
| 213 | a=2^62+2^47+2 and b=2^64-1, then the new c and
|
---|
| 214 | the new x can be formed with shifts, tests and +/-'s,
|
---|
| 215 | again with a little fiddling because b=2^64-1 rather
|
---|
| 216 | than 2^64. (The latter is not an optimal choice because,
|
---|
| 217 | being a square, it cannot be a primitive root of the
|
---|
| 218 | prime a*b^k+1, where 'k' is the 'lag':
|
---|
| 219 | x(n)=a*x(n-k)+carry mod b.)
|
---|
| 220 | But the multiplier a=2^62+2^47+2 makes a*b^4+1 a prime for
|
---|
| 221 | which b=2^64-1 is a primitive root, and getting the new x and
|
---|
| 222 | new c can be done with arithmetic on integers the size of x.
|
---|
| 223 | */
|
---|
[9262] | 224 |
|
---|
| 225 | struct RndCtx
|
---|
[728] | 226 | {
|
---|
[9262] | 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 | };
|
---|
| 235 | typedef struct RndCtx RNDCTX;
|
---|
| 236 | typedef RNDCTX *PRNDCTX;
|
---|
| 237 |
|
---|
| 238 | /**
|
---|
[11353] | 239 | * Initialize seeds.
|
---|
| 240 | *
|
---|
[9262] | 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 | */
|
---|
[9264] | 247 | RTDECL(int) RTPRandInit(PRNDCTX pCtx, uint32_t u32Seed)
|
---|
[9262] | 248 | {
|
---|
[9264] | 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;
|
---|
[9490] | 255 | pCtx->y = 17280675555674358941ULL;
|
---|
| 256 | pCtx->z = 6376492577913983186ULL;
|
---|
| 257 | pCtx->w = 9064188857900113776ULL;
|
---|
[9264] | 258 | pCtx->c = 123456789;
|
---|
| 259 | pCtx->u32x = 2282008;
|
---|
| 260 | pCtx->u32y = u32Seed;
|
---|
[9262] | 261 | return VINF_SUCCESS;
|
---|
| 262 | }
|
---|
| 263 |
|
---|
[9264] | 264 | RTDECL(uint32_t) RTPRandGetSeedInfo(PRNDCTX pCtx)
|
---|
[9262] | 265 | {
|
---|
[9264] | 266 | return pCtx->u32y;
|
---|
[9262] | 267 | }
|
---|
| 268 |
|
---|
| 269 | /**
|
---|
| 270 | * Generate a 64-bit unsigned random number.
|
---|
| 271 | *
|
---|
| 272 | * @returns The pseudo random number.
|
---|
| 273 | */
|
---|
| 274 | RTDECL(uint64_t) RTPRandU64(PRNDCTX pCtx)
|
---|
| 275 | {
|
---|
[11353] | 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 | }
|
---|
[9262] | 283 |
|
---|
| 284 | /**
|
---|
[11353] | 285 | * Generate a 64-bit unsigned pseudo random number in the set
|
---|
| 286 | * [u64First..u64Last].
|
---|
[9262] | 287 | *
|
---|
| 288 | * @returns The pseudo random number.
|
---|
| 289 | * @param u64First First number in the set.
|
---|
| 290 | * @param u64Last Last number in the set.
|
---|
| 291 | */
|
---|
| 292 | RTDECL(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 | */
|
---|
| 313 | RTDECL(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 );
|
---|
[11353] | 320 | }
|
---|
[9262] | 321 |
|
---|
| 322 | /**
|
---|
[11353] | 323 | * Generate a 32-bit unsigned pseudo random number in the set
|
---|
| 324 | * [u32First..u32Last].
|
---|
[9262] | 325 | *
|
---|
| 326 | * @returns The pseudo random number.
|
---|
| 327 | * @param u32First First number in the set.
|
---|
| 328 | * @param u32Last Last number in the set.
|
---|
| 329 | */
|
---|
| 330 | RTDECL(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 |
|
---|
| 348 | struct Segment
|
---|
| 349 | {
|
---|
| 350 | uint64_t u64Offset;
|
---|
| 351 | uint32_t u32Length;
|
---|
| 352 | uint32_t u8Value;
|
---|
| 353 | };
|
---|
| 354 | typedef struct Segment *PSEGMENT;
|
---|
| 355 |
|
---|
[9264] | 356 | static void initializeRandomGenerator(PRNDCTX pCtx, uint32_t u32Seed)
|
---|
[9262] | 357 | {
|
---|
[9264] | 358 | int rc = RTPRandInit(pCtx, u32Seed);
|
---|
[13835] | 359 | if (RT_FAILURE(rc))
|
---|
[13837] | 360 | RTPrintf("ERROR: Failed to initialize random generator. RC=%Rrc\n", rc);
|
---|
[9262] | 361 | else
|
---|
| 362 | {
|
---|
[11353] | 363 | RTPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx));
|
---|
| 364 | RTLogPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx));
|
---|
[9262] | 365 | }
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | static 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 |
|
---|
| 374 | static 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 | {
|
---|
[9264] | 380 | bool fDuplicateFound;
|
---|
[9262] | 381 | do
|
---|
| 382 | {
|
---|
| 383 | pSegment[i].u64Offset = RTPRandU64Ex(pCtx, 0, u64DiskSize / u32SectorSize - 1) * u32SectorSize;
|
---|
[9264] | 384 | fDuplicateFound = false;
|
---|
[9262] | 385 | for (uint32_t j = 0; j < i; j++)
|
---|
| 386 | if (pSegment[i].u64Offset == pSegment[j].u64Offset)
|
---|
[9264] | 387 | {
|
---|
[9262] | 388 | fDuplicateFound = true;
|
---|
[9264] | 389 | break;
|
---|
| 390 | }
|
---|
[9262] | 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;
|
---|
[9418] | 403 | Assert(pSegment[i].u32Length <= u32MaxSegmentSize);
|
---|
[9262] | 404 | pSegment[i].u8Value = RTPRandU32Ex(pCtx, (uint32_t)u8ValueLow, (uint32_t)u8ValueHigh);
|
---|
| 405 | }
|
---|
| 406 | }
|
---|
| 407 |
|
---|
[9418] | 408 | static void mergeSegments(PSEGMENT pBaseSegment, PSEGMENT pDiffSegment, PSEGMENT pMergeSegment, uint32_t u32MaxLength)
|
---|
[9262] | 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;
|
---|
[9418] | 420 | Assert(pMergeSegment->u32Length <= u32MaxLength);
|
---|
[9262] | 421 | if (pBaseSegment->u64Offset + pBaseSegment->u32Length >
|
---|
| 422 | pDiffSegment->u64Offset + pDiffSegment->u32Length)
|
---|
| 423 | {
|
---|
[9418] | 424 | pBaseSegment->u32Length -= pDiffSegment->u64Offset + pDiffSegment->u32Length - pBaseSegment->u64Offset;
|
---|
| 425 | Assert(pBaseSegment->u32Length <= u32MaxLength);
|
---|
[9262] | 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;
|
---|
[9418] | 446 | Assert(pBaseSegment->u32Length <= u32MaxLength);
|
---|
[9262] | 447 | pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length;
|
---|
| 448 | pDiffSegment++;
|
---|
| 449 | pMergeSegment++;
|
---|
| 450 | }
|
---|
| 451 | else
|
---|
| 452 | pBaseSegment++;
|
---|
| 453 | }
|
---|
| 454 | }
|
---|
| 455 | }
|
---|
| 456 | }
|
---|
| 457 |
|
---|
| 458 | static 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 |
|
---|
| 469 | static int readAndCompareSegments(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment)
|
---|
| 470 | {
|
---|
| 471 | while (pSegment->u32Length)
|
---|
| 472 | {
|
---|
| 473 | int rc = VDRead(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length);
|
---|
[13835] | 474 | if (RT_FAILURE(rc))
|
---|
[9262] | 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 | {
|
---|
[9528] | 484 | RTPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n",
|
---|
[9262] | 485 | pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i],
|
---|
| 486 | pSegment->u8Value);
|
---|
[9528] | 487 | RTLogPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n",
|
---|
[9264] | 488 | pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i],
|
---|
| 489 | pSegment->u8Value);
|
---|
[9262] | 490 | return VERR_INTERNAL_ERROR;
|
---|
| 491 | }
|
---|
| 492 | }
|
---|
| 493 | pSegment++;
|
---|
| 494 | }
|
---|
| 495 |
|
---|
| 496 | return VINF_SUCCESS;
|
---|
| 497 | }
|
---|
| 498 |
|
---|
| 499 | static int tstVDOpenCreateWriteMerge(const char *pszBackend,
|
---|
| 500 | const char *pszBaseFilename,
|
---|
| 501 | const char *pszDiffFilename,
|
---|
[9264] | 502 | uint32_t u32Seed)
|
---|
[9262] | 503 | {
|
---|
[7895] | 504 | int rc;
|
---|
[9262] | 505 | PVBOXHDD pVD = NULL;
|
---|
| 506 | char *pszFormat;
|
---|
[32536] | 507 | VDGEOMETRY PCHS = { 0, 0, 0 };
|
---|
| 508 | VDGEOMETRY LCHS = { 0, 0, 0 };
|
---|
| 509 | uint64_t u64DiskSize = 1000 * _1M;
|
---|
[9262] | 510 | uint32_t u32SectorSize = 512;
|
---|
[11435] | 511 | PVDINTERFACE pVDIfs = NULL;
|
---|
[10715] | 512 | VDINTERFACE VDIError;
|
---|
| 513 | VDINTERFACEERROR VDIErrorCallbacks;
|
---|
[7895] | 514 |
|
---|
[9262] | 515 | #define CHECK(str) \
|
---|
| 516 | do \
|
---|
| 517 | { \
|
---|
[13837] | 518 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
[13835] | 519 | if (RT_FAILURE(rc)) \
|
---|
[9262] | 520 | { \
|
---|
[13295] | 521 | if (pvBuf) \
|
---|
| 522 | RTMemFree(pvBuf); \
|
---|
| 523 | VDDestroy(pVD); \
|
---|
[9262] | 524 | return rc; \
|
---|
| 525 | } \
|
---|
| 526 | } while (0)
|
---|
| 527 |
|
---|
[13295] | 528 | void *pvBuf = RTMemAlloc(_1M);
|
---|
| 529 |
|
---|
[10715] | 530 | /* Create error interface. */
|
---|
| 531 | VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
|
---|
| 532 | VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
|
---|
| 533 | VDIErrorCallbacks.pfnError = tstVDError;
|
---|
[26988] | 534 | VDIErrorCallbacks.pfnMessage = tstVDMessage;
|
---|
[10715] | 535 |
|
---|
[11435] | 536 | rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
|
---|
| 537 | NULL, &pVDIfs);
|
---|
[10715] | 538 | AssertRC(rc);
|
---|
| 539 |
|
---|
| 540 |
|
---|
| 541 | rc = VDCreate(&VDIError, &pVD);
|
---|
[9262] | 542 | CHECK("VDCreate()");
|
---|
| 543 |
|
---|
| 544 | RTFILE File;
|
---|
[23973] | 545 | rc = RTFileOpen(&File, pszBaseFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
|
---|
[13835] | 546 | if (RT_SUCCESS(rc))
|
---|
[9262] | 547 | {
|
---|
| 548 | RTFileClose(File);
|
---|
[32536] | 549 | rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
|
---|
| 550 | pszBaseFilename, &pszFormat);
|
---|
[13837] | 551 | RTPrintf("VDGetFormat() pszFormat=%s rc=%Rrc\n", pszFormat, rc);
|
---|
[13835] | 552 | if (RT_SUCCESS(rc) && strcmp(pszFormat, pszBackend))
|
---|
[9262] | 553 | {
|
---|
| 554 | rc = VERR_GENERAL_FAILURE;
|
---|
| 555 | RTPrintf("VDGetFormat() returned incorrect backend name\n");
|
---|
| 556 | }
|
---|
| 557 | RTStrFree(pszFormat);
|
---|
| 558 | CHECK("VDGetFormat()");
|
---|
| 559 |
|
---|
[11444] | 560 | rc = VDOpen(pVD, pszBackend, pszBaseFilename, VD_OPEN_FLAGS_NORMAL,
|
---|
| 561 | NULL);
|
---|
[9262] | 562 | CHECK("VDOpen()");
|
---|
| 563 | }
|
---|
| 564 | else
|
---|
| 565 | {
|
---|
[17970] | 566 | rc = VDCreateBase(pVD, pszBackend, pszBaseFilename, u64DiskSize,
|
---|
[9262] | 567 | VD_IMAGE_FLAGS_NONE, "Test image",
|
---|
[11353] | 568 | &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
|
---|
[9262] | 569 | NULL, NULL);
|
---|
| 570 | CHECK("VDCreateBase()");
|
---|
| 571 | }
|
---|
| 572 |
|
---|
[9418] | 573 | int nSegments = 100;
|
---|
[9262] | 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;
|
---|
[9264] | 580 | initializeRandomGenerator(&ctx, u32Seed);
|
---|
[9262] | 581 | generateRandomSegments(&ctx, paBaseSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u);
|
---|
| 582 | generateRandomSegments(&ctx, paDiffSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 128u, 255u);
|
---|
| 583 |
|
---|
[9734] | 584 | /*PSEGMENT pSegment;
|
---|
| 585 | RTPrintf("Base segments:\n");
|
---|
[9262] | 586 | for (pSegment = paBaseSegments; pSegment->u32Length; pSegment++)
|
---|
[9528] | 587 | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
|
---|
[9262] | 588 | writeSegmentsToDisk(pVD, pvBuf, paBaseSegments);
|
---|
| 589 |
|
---|
| 590 | rc = VDCreateDiff(pVD, pszBackend, pszDiffFilename,
|
---|
[15591] | 591 | VD_IMAGE_FLAGS_NONE, "Test diff image", NULL, NULL,
|
---|
[9262] | 592 | VD_OPEN_FLAGS_NORMAL, NULL, NULL);
|
---|
| 593 | CHECK("VDCreateDiff()");
|
---|
| 594 |
|
---|
| 595 | /*RTPrintf("\nDiff segments:\n");
|
---|
| 596 | for (pSegment = paDiffSegments; pSegment->u32Length; pSegment++)
|
---|
[9528] | 597 | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
|
---|
[9262] | 598 | writeSegmentsToDisk(pVD, pvBuf, paDiffSegments);
|
---|
| 599 |
|
---|
| 600 | VDDumpImages(pVD);
|
---|
| 601 |
|
---|
| 602 | RTPrintf("Merging diff into base..\n");
|
---|
[11444] | 603 | rc = VDMerge(pVD, VD_LAST_IMAGE, 0, NULL);
|
---|
[9262] | 604 | CHECK("VDMerge()");
|
---|
| 605 |
|
---|
[9418] | 606 | mergeSegments(paBaseSegments, paDiffSegments, paMergeSegments, _1M);
|
---|
[9262] | 607 | /*RTPrintf("\nMerged segments:\n");
|
---|
| 608 | for (pSegment = paMergeSegments; pSegment->u32Length; pSegment++)
|
---|
[9528] | 609 | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
|
---|
[9262] | 610 | rc = readAndCompareSegments(pVD, pvBuf, paMergeSegments);
|
---|
| 611 | CHECK("readAndCompareSegments()");
|
---|
| 612 |
|
---|
| 613 | RTMemFree(paMergeSegments);
|
---|
| 614 | RTMemFree(paDiffSegments);
|
---|
| 615 | RTMemFree(paBaseSegments);
|
---|
| 616 |
|
---|
| 617 | VDDumpImages(pVD);
|
---|
| 618 |
|
---|
[13295] | 619 | VDDestroy(pVD);
|
---|
| 620 | if (pvBuf)
|
---|
| 621 | RTMemFree(pvBuf);
|
---|
[9262] | 622 | #undef CHECK
|
---|
| 623 | return 0;
|
---|
| 624 | }
|
---|
| 625 |
|
---|
[9418] | 626 | static int tstVDCreateWriteOpenRead(const char *pszBackend,
|
---|
| 627 | const char *pszFilename,
|
---|
| 628 | uint32_t u32Seed)
|
---|
| 629 | {
|
---|
| 630 | int rc;
|
---|
| 631 | PVBOXHDD pVD = NULL;
|
---|
[32536] | 632 | VDGEOMETRY PCHS = { 0, 0, 0 };
|
---|
| 633 | VDGEOMETRY LCHS = { 0, 0, 0 };
|
---|
| 634 | uint64_t u64DiskSize = 1000 * _1M;
|
---|
[9418] | 635 | uint32_t u32SectorSize = 512;
|
---|
[26988] | 636 | PVDINTERFACE pVDIfs = NULL;
|
---|
[10715] | 637 | VDINTERFACE VDIError;
|
---|
| 638 | VDINTERFACEERROR VDIErrorCallbacks;
|
---|
[9418] | 639 |
|
---|
| 640 | #define CHECK(str) \
|
---|
| 641 | do \
|
---|
| 642 | { \
|
---|
[13837] | 643 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
[13835] | 644 | if (RT_FAILURE(rc)) \
|
---|
[9418] | 645 | { \
|
---|
[13340] | 646 | if (pvBuf) \
|
---|
| 647 | RTMemFree(pvBuf); \
|
---|
[13295] | 648 | VDDestroy(pVD); \
|
---|
[9418] | 649 | return rc; \
|
---|
| 650 | } \
|
---|
| 651 | } while (0)
|
---|
| 652 |
|
---|
[13340] | 653 | void *pvBuf = RTMemAlloc(_1M);
|
---|
| 654 |
|
---|
[10715] | 655 | /* Create error interface. */
|
---|
| 656 | VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
|
---|
| 657 | VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
|
---|
| 658 | VDIErrorCallbacks.pfnError = tstVDError;
|
---|
[26988] | 659 | VDIErrorCallbacks.pfnMessage = tstVDMessage;
|
---|
[10715] | 660 |
|
---|
[11435] | 661 | rc = VDInterfaceAdd(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
|
---|
| 662 | NULL, &pVDIfs);
|
---|
[10715] | 663 | AssertRC(rc);
|
---|
| 664 |
|
---|
| 665 |
|
---|
| 666 | rc = VDCreate(&VDIError, &pVD);
|
---|
[9418] | 667 | CHECK("VDCreate()");
|
---|
| 668 |
|
---|
| 669 | RTFILE File;
|
---|
[23973] | 670 | rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
|
---|
[13835] | 671 | if (RT_SUCCESS(rc))
|
---|
[9418] | 672 | {
|
---|
| 673 | RTFileClose(File);
|
---|
| 674 | RTFileDelete(pszFilename);
|
---|
| 675 | }
|
---|
| 676 |
|
---|
[17970] | 677 | rc = VDCreateBase(pVD, pszBackend, pszFilename, u64DiskSize,
|
---|
[9418] | 678 | VD_IMAGE_FLAGS_NONE, "Test image",
|
---|
[11353] | 679 | &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
|
---|
[9418] | 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);
|
---|
[9528] | 690 | /*for (PSEGMENT pSegment = paSegments; pSegment->u32Length; pSegment++)
|
---|
| 691 | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/
|
---|
[9418] | 692 |
|
---|
| 693 | writeSegmentsToDisk(pVD, pvBuf, paSegments);
|
---|
| 694 |
|
---|
| 695 | VDCloseAll(pVD);
|
---|
| 696 |
|
---|
[11444] | 697 | rc = VDOpen(pVD, pszBackend, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
|
---|
[9418] | 698 | CHECK("VDOpen()");
|
---|
| 699 | rc = readAndCompareSegments(pVD, pvBuf, paSegments);
|
---|
| 700 | CHECK("readAndCompareSegments()");
|
---|
| 701 |
|
---|
| 702 | RTMemFree(paSegments);
|
---|
| 703 |
|
---|
[13295] | 704 | VDDestroy(pVD);
|
---|
[13340] | 705 | if (pvBuf)
|
---|
| 706 | RTMemFree(pvBuf);
|
---|
[9418] | 707 | #undef CHECK
|
---|
| 708 | return 0;
|
---|
| 709 | }
|
---|
| 710 |
|
---|
[13268] | 711 | static 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;
|
---|
[9734] | 718 |
|
---|
[13268] | 719 | #define CHECK(str) \
|
---|
| 720 | do \
|
---|
| 721 | { \
|
---|
[13837] | 722 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
[13835] | 723 | if (RT_FAILURE(rc)) \
|
---|
[13268] | 724 | { \
|
---|
[13295] | 725 | VDDestroy(pVD); \
|
---|
[13268] | 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;
|
---|
[26988] | 734 | VDIErrorCallbacks.pfnMessage = tstVDMessage;
|
---|
[13268] | 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()");
|
---|
[17836] | 745 | rc = VDCopy(pVD, 0, pVD, "VMDK", dst, true, 0, VD_IMAGE_FLAGS_NONE, NULL, NULL, NULL, NULL);
|
---|
[13268] | 746 | CHECK("VDCopy()");
|
---|
| 747 |
|
---|
[13295] | 748 | VDDestroy(pVD);
|
---|
[13268] | 749 | #undef CHECK
|
---|
| 750 | return 0;
|
---|
| 751 | }
|
---|
| 752 |
|
---|
| 753 | static int tstVmdkCreateRenameOpen(const char *src, const char *dst,
|
---|
[17970] | 754 | uint64_t cbSize, unsigned uFlags)
|
---|
[13268] | 755 | {
|
---|
[17970] | 756 | int rc = tstVDCreateDelete("VMDK", src, cbSize, uFlags, false);
|
---|
[13835] | 757 | if (RT_FAILURE(rc))
|
---|
[13268] | 758 | return rc;
|
---|
| 759 |
|
---|
| 760 | rc = tstVmdkRename(src, dst);
|
---|
[13835] | 761 | if (RT_FAILURE(rc))
|
---|
[13268] | 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 | { \
|
---|
[13837] | 772 | RTPrintf("%s rc=%Rrc\n", str, rc); \
|
---|
[13835] | 773 | if (RT_FAILURE(rc)) \
|
---|
[13268] | 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;
|
---|
[26988] | 784 | VDIErrorCallbacks.pfnMessage = tstVDMessage;
|
---|
[13268] | 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 |
|
---|
| 809 | static void tstVmdk()
|
---|
| 810 | {
|
---|
| 811 | int rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", "tmpVDRename.vmdk", _4G,
|
---|
[17970] | 812 | VD_IMAGE_FLAGS_NONE);
|
---|
[13835] | 813 | if (RT_FAILURE(rc))
|
---|
[13268] | 814 | {
|
---|
[13837] | 815 | RTPrintf("tstVD: VMDK rename (single extent, embedded descriptor, same dir) test failed! rc=%Rrc\n", rc);
|
---|
[13268] | 816 | g_cErrors++;
|
---|
| 817 | }
|
---|
| 818 | rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", "tmpVDRename.vmdk", _4G,
|
---|
[17970] | 819 | VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
|
---|
[13835] | 820 | if (RT_FAILURE(rc))
|
---|
[13268] | 821 | {
|
---|
[13837] | 822 | RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, same dir) test failed! rc=%Rrc\n", rc);
|
---|
[13268] | 823 | g_cErrors++;
|
---|
| 824 | }
|
---|
| 825 | rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
|
---|
[17970] | 826 | VD_IMAGE_FLAGS_NONE);
|
---|
[13835] | 827 | if (RT_FAILURE(rc))
|
---|
[13268] | 828 | {
|
---|
[13837] | 829 | RTPrintf("tstVD: VMDK rename (single extent, embedded descriptor, another dir) test failed! rc=%Rrc\n", rc);
|
---|
[13268] | 830 | g_cErrors++;
|
---|
| 831 | }
|
---|
| 832 | rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
|
---|
[17970] | 833 | VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
|
---|
[13835] | 834 | if (RT_FAILURE(rc))
|
---|
[13268] | 835 | {
|
---|
[13837] | 836 | RTPrintf("tstVD: VMDK rename (multiple extent, separate descriptor, another dir) test failed! rc=%Rrc\n", rc);
|
---|
[13268] | 837 | g_cErrors++;
|
---|
| 838 | }
|
---|
| 839 |
|
---|
| 840 | RTFILE File;
|
---|
[23973] | 841 | rc = RTFileOpen(&File, DST_PATH, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE);
|
---|
[13835] | 842 | if (RT_SUCCESS(rc))
|
---|
[13268] | 843 | RTFileClose(File);
|
---|
| 844 |
|
---|
| 845 | rc = tstVmdkCreateRenameOpen("tmpVDCreate.vmdk", DST_PATH, _4G,
|
---|
[17970] | 846 | VD_VMDK_IMAGE_FLAGS_SPLIT_2G);
|
---|
[13835] | 847 | if (RT_SUCCESS(rc))
|
---|
[13268] | 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 |
|
---|
[9262] | 859 | int main(int argc, char *argv[])
|
---|
| 860 | {
|
---|
[14817] | 861 | RTR3Init();
|
---|
[9262] | 862 | int rc;
|
---|
| 863 |
|
---|
[9264] | 864 | uint32_t u32Seed = 0; // Means choose random
|
---|
[9262] | 865 |
|
---|
| 866 | if (argc > 1)
|
---|
[9264] | 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 | }
|
---|
[9262] | 873 |
|
---|
[7895] | 874 | RTPrintf("tstVD: TESTING...\n");
|
---|
[728] | 875 |
|
---|
[7895] | 876 | /*
|
---|
| 877 | * Clean up potential leftovers from previous unsuccessful runs.
|
---|
| 878 | */
|
---|
[8248] | 879 | RTFileDelete("tmpVDCreate.vdi");
|
---|
| 880 | RTFileDelete("tmpVDCreate.vmdk");
|
---|
[9418] | 881 | RTFileDelete("tmpVDCreate.vhd");
|
---|
[7895] | 882 | RTFileDelete("tmpVDBase.vdi");
|
---|
| 883 | RTFileDelete("tmpVDDiff.vdi");
|
---|
| 884 | RTFileDelete("tmpVDBase.vmdk");
|
---|
| 885 | RTFileDelete("tmpVDDiff.vmdk");
|
---|
[9418] | 886 | RTFileDelete("tmpVDBase.vhd");
|
---|
| 887 | RTFileDelete("tmpVDDiff.vhd");
|
---|
[13268] | 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);
|
---|
[13835] | 903 | if (RT_FAILURE(rc))
|
---|
[13268] | 904 | {
|
---|
[13837] | 905 | RTPrintf("tstVD: Failed to create 'tmp' directory! rc=%Rrc\n", rc);
|
---|
[13268] | 906 | g_cErrors++;
|
---|
| 907 | }
|
---|
| 908 | }
|
---|
| 909 |
|
---|
[13295] | 910 | #ifdef VMDK_TEST
|
---|
[13268] | 911 | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
|
---|
[17970] | 912 | VD_IMAGE_FLAGS_NONE, true);
|
---|
[13835] | 913 | if (RT_FAILURE(rc))
|
---|
[13268] | 914 | {
|
---|
[13837] | 915 | RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
|
---|
[13268] | 916 | g_cErrors++;
|
---|
| 917 | }
|
---|
| 918 | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
|
---|
[17970] | 919 | VD_IMAGE_FLAGS_NONE, false);
|
---|
[13835] | 920 | if (RT_FAILURE(rc))
|
---|
[13268] | 921 | {
|
---|
[13837] | 922 | RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
|
---|
[13268] | 923 | g_cErrors++;
|
---|
| 924 | }
|
---|
| 925 | rc = tstVDOpenDelete("VMDK", "tmpVDCreate.vmdk");
|
---|
[13835] | 926 | if (RT_FAILURE(rc))
|
---|
[13268] | 927 | {
|
---|
[13837] | 928 | RTPrintf("tstVD: VMDK delete test failed! rc=%Rrc\n", rc);
|
---|
[13268] | 929 | g_cErrors++;
|
---|
| 930 | }
|
---|
[13295] | 931 |
|
---|
[13268] | 932 | tstVmdk();
|
---|
[13295] | 933 | #endif /* VMDK_TEST */
|
---|
| 934 | #ifdef VDI_TEST
|
---|
[8248] | 935 | rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
|
---|
[17970] | 936 | VD_IMAGE_FLAGS_NONE, true);
|
---|
[13835] | 937 | if (RT_FAILURE(rc))
|
---|
[8248] | 938 | {
|
---|
[13837] | 939 | RTPrintf("tstVD: dynamic VDI create test failed! rc=%Rrc\n", rc);
|
---|
[8248] | 940 | g_cErrors++;
|
---|
| 941 | }
|
---|
| 942 | rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G,
|
---|
[17970] | 943 | VD_IMAGE_FLAGS_NONE, true);
|
---|
[13835] | 944 | if (RT_FAILURE(rc))
|
---|
[8248] | 945 | {
|
---|
[13837] | 946 | RTPrintf("tstVD: fixed VDI create test failed! rc=%Rrc\n", rc);
|
---|
[8248] | 947 | g_cErrors++;
|
---|
| 948 | }
|
---|
[13295] | 949 | #endif /* VDI_TEST */
|
---|
| 950 | #ifdef VMDK_TEST
|
---|
[8248] | 951 | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
|
---|
[17970] | 952 | VD_IMAGE_FLAGS_NONE, true);
|
---|
[13835] | 953 | if (RT_FAILURE(rc))
|
---|
[8248] | 954 | {
|
---|
[13837] | 955 | RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Rrc\n", rc);
|
---|
[8248] | 956 | g_cErrors++;
|
---|
| 957 | }
|
---|
| 958 | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
|
---|
[17970] | 959 | VD_VMDK_IMAGE_FLAGS_SPLIT_2G, true);
|
---|
[13835] | 960 | if (RT_FAILURE(rc))
|
---|
[8248] | 961 | {
|
---|
[13837] | 962 | RTPrintf("tstVD: dynamic split VMDK create test failed! rc=%Rrc\n", rc);
|
---|
[8248] | 963 | g_cErrors++;
|
---|
| 964 | }
|
---|
| 965 | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
|
---|
[17970] | 966 | VD_IMAGE_FLAGS_FIXED, true);
|
---|
[13835] | 967 | if (RT_FAILURE(rc))
|
---|
[8248] | 968 | {
|
---|
[13837] | 969 | RTPrintf("tstVD: fixed VMDK create test failed! rc=%Rrc\n", rc);
|
---|
[8248] | 970 | g_cErrors++;
|
---|
| 971 | }
|
---|
| 972 | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G,
|
---|
[17970] | 973 | VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_SPLIT_2G,
|
---|
[8248] | 974 | true);
|
---|
[13835] | 975 | if (RT_FAILURE(rc))
|
---|
[8248] | 976 | {
|
---|
[13837] | 977 | RTPrintf("tstVD: fixed split VMDK create test failed! rc=%Rrc\n", rc);
|
---|
[8248] | 978 | g_cErrors++;
|
---|
| 979 | }
|
---|
[13295] | 980 | #endif /* VMDK_TEST */
|
---|
| 981 | #ifdef VHD_TEST
|
---|
[9418] | 982 | rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
|
---|
[17970] | 983 | VD_IMAGE_FLAGS_NONE, true);
|
---|
[13835] | 984 | if (RT_FAILURE(rc))
|
---|
[9418] | 985 | {
|
---|
[13837] | 986 | RTPrintf("tstVD: dynamic VHD create test failed! rc=%Rrc\n", rc);
|
---|
[9418] | 987 | g_cErrors++;
|
---|
| 988 | }
|
---|
| 989 | rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G,
|
---|
[17970] | 990 | VD_IMAGE_FLAGS_FIXED, true);
|
---|
[13835] | 991 | if (RT_FAILURE(rc))
|
---|
[9418] | 992 | {
|
---|
[13837] | 993 | RTPrintf("tstVD: fixed VHD create test failed! rc=%Rrc\n", rc);
|
---|
[9418] | 994 | g_cErrors++;
|
---|
| 995 | }
|
---|
[13295] | 996 | #endif /* VHD_TEST */
|
---|
| 997 | #ifdef VDI_TEST
|
---|
[9264] | 998 | rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
|
---|
[13835] | 999 | if (RT_FAILURE(rc))
|
---|
[7895] | 1000 | {
|
---|
[13837] | 1001 | RTPrintf("tstVD: VDI test failed (new image)! rc=%Rrc\n", rc);
|
---|
[7895] | 1002 | g_cErrors++;
|
---|
| 1003 | }
|
---|
[9264] | 1004 | rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed);
|
---|
[13835] | 1005 | if (RT_FAILURE(rc))
|
---|
[7895] | 1006 | {
|
---|
[13837] | 1007 | RTPrintf("tstVD: VDI test failed (existing image)! rc=%Rrc\n", rc);
|
---|
[7895] | 1008 | g_cErrors++;
|
---|
| 1009 | }
|
---|
[13295] | 1010 | #endif /* VDI_TEST */
|
---|
| 1011 | #ifdef VMDK_TEST
|
---|
[9264] | 1012 | rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
|
---|
[13835] | 1013 | if (RT_FAILURE(rc))
|
---|
[7895] | 1014 | {
|
---|
[13837] | 1015 | RTPrintf("tstVD: VMDK test failed (new image)! rc=%Rrc\n", rc);
|
---|
[7895] | 1016 | g_cErrors++;
|
---|
| 1017 | }
|
---|
[9264] | 1018 | rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed);
|
---|
[13835] | 1019 | if (RT_FAILURE(rc))
|
---|
[7895] | 1020 | {
|
---|
[13837] | 1021 | RTPrintf("tstVD: VMDK test failed (existing image)! rc=%Rrc\n", rc);
|
---|
[7895] | 1022 | g_cErrors++;
|
---|
| 1023 | }
|
---|
[13295] | 1024 | #endif /* VMDK_TEST */
|
---|
| 1025 | #ifdef VHD_TEST
|
---|
[9418] | 1026 | rc = tstVDCreateWriteOpenRead("VHD", "tmpVDCreate.vhd", u32Seed);
|
---|
[13835] | 1027 | if (RT_FAILURE(rc))
|
---|
[9418] | 1028 | {
|
---|
[13837] | 1029 | RTPrintf("tstVD: VHD test failed (creating image)! rc=%Rrc\n", rc);
|
---|
[9418] | 1030 | g_cErrors++;
|
---|
| 1031 | }
|
---|
[9528] | 1032 |
|
---|
[9418] | 1033 | rc = tstVDOpenCreateWriteMerge("VHD", "tmpVDBase.vhd", "tmpVDDiff.vhd", u32Seed);
|
---|
[13835] | 1034 | if (RT_FAILURE(rc))
|
---|
[9418] | 1035 | {
|
---|
[13837] | 1036 | RTPrintf("tstVD: VHD test failed (existing image)! rc=%Rrc\n", rc);
|
---|
[9418] | 1037 | g_cErrors++;
|
---|
| 1038 | }
|
---|
[13295] | 1039 | #endif /* VHD_TEST */
|
---|
[9528] | 1040 |
|
---|
[7895] | 1041 | /*
|
---|
| 1042 | * Clean up any leftovers.
|
---|
| 1043 | */
|
---|
[8248] | 1044 | RTFileDelete("tmpVDCreate.vdi");
|
---|
| 1045 | RTFileDelete("tmpVDCreate.vmdk");
|
---|
[9418] | 1046 | RTFileDelete("tmpVDCreate.vhd");
|
---|
[7895] | 1047 | RTFileDelete("tmpVDBase.vdi");
|
---|
| 1048 | RTFileDelete("tmpVDDiff.vdi");
|
---|
| 1049 | RTFileDelete("tmpVDBase.vmdk");
|
---|
| 1050 | RTFileDelete("tmpVDDiff.vmdk");
|
---|
[9418] | 1051 | RTFileDelete("tmpVDBase.vhd");
|
---|
| 1052 | RTFileDelete("tmpVDDiff.vhd");
|
---|
[13268] | 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");
|
---|
[7895] | 1060 |
|
---|
[14855] | 1061 | rc = VDShutdown();
|
---|
| 1062 | if (RT_FAILURE(rc))
|
---|
| 1063 | {
|
---|
| 1064 | RTPrintf("tstVD: unloading backends failed! rc=%Rrc\n", rc);
|
---|
| 1065 | g_cErrors++;
|
---|
| 1066 | }
|
---|
| 1067 | /*
|
---|
[7895] | 1068 | * Summary
|
---|
| 1069 | */
|
---|
| 1070 | if (!g_cErrors)
|
---|
| 1071 | RTPrintf("tstVD: SUCCESS\n");
|
---|
[728] | 1072 | else
|
---|
[7895] | 1073 | RTPrintf("tstVD: FAILURE - %d errors\n", g_cErrors);
|
---|
[728] | 1074 |
|
---|
[7895] | 1075 | return !!g_cErrors;
|
---|
[1] | 1076 | }
|
---|
| 1077 |
|
---|