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