| 77 | | rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks, |
|---|
| 78 | | NULL, NULL); |
|---|
| 79 | | AssertRC(rc); |
|---|
| 80 | | |
|---|
| 81 | | rc = VDCreate(&VDIError, &pVD); |
|---|
| 82 | | CHECK("VDCreate()"); |
|---|
| 83 | | |
|---|
| 84 | | rc = VDCreateBase(pVD, pszBackend, pszFilename, enmType, cbSize, |
|---|
| 85 | | uFlags, "Test image", &PCHS, &LCHS, NULL, |
|---|
| 86 | | VD_OPEN_FLAGS_NORMAL, NULL, NULL); |
|---|
| 87 | | CHECK("VDCreateBase()"); |
|---|
| 88 | | |
|---|
| 89 | | VDDumpImages(pVD); |
|---|
| 90 | | |
|---|
| 91 | | VDClose(pVD, fDelete); |
|---|
| 92 | | #undef CHECK |
|---|
| 93 | | return 0; |
|---|
| 94 | | } |
|---|
| 95 | | |
|---|
| 96 | | |
|---|
| 97 | | #undef RTDECL |
|---|
| 98 | | #define RTDECL(x) static x |
|---|
| 99 | | |
|---|
| 100 | | /* Start of IPRT code */ |
|---|
| 101 | | |
|---|
| 102 | | /** |
|---|
| 103 | | * The following code is based on the work of George Marsaglia |
|---|
| 104 | | * taken from |
|---|
| 105 | | * http://groups.google.ws/group/comp.sys.sun.admin/msg/7c667186f6cbf354 |
|---|
| 106 | | * and |
|---|
| 107 | | * http://groups.google.ws/group/comp.lang.c/msg/0e170777c6e79e8d |
|---|
| 108 | | */ |
|---|
| 109 | | |
|---|
| 110 | | /* |
|---|
| 111 | | A C version of a very very good 64-bit RNG is given below. |
|---|
| 112 | | You should be able to adapt it to your particular needs. |
|---|
| 113 | | |
|---|
| 114 | | It is based on the complimentary-multiple-with-carry |
|---|
| 115 | | sequence |
|---|
| 116 | | x(n)=a*x(n-4)+carry mod 2^64-1, |
|---|
| 117 | | which works as follows: |
|---|
| 118 | | Assume a certain multiplier 'a' and a base 'b'. |
|---|
| 119 | | Given a current x value and a current carry 'c', |
|---|
| 120 | | form: t=a*x+c |
|---|
| 121 | | Then the new carry is c=floor(t/b) |
|---|
| 122 | | and the new x value is x = b-1-(t mod b). |
|---|
| 123 | | |
|---|
| 124 | | |
|---|
| 125 | | Ordinarily, for 32-bit mwc or cmwc sequences, the |
|---|
| 126 | | value t=a*x+c can be formed in 64 bits, then the new c |
|---|
| 127 | | is the top and the new x the bottom 32 bits (with a little |
|---|
| 128 | | fiddling when b=2^32-1 and cmwc rather than mwc.) |
|---|
| 129 | | |
|---|
| 130 | | |
|---|
| 131 | | To generate 64-bit x's, it is difficult to form |
|---|
| 132 | | t=a*x+c in 128 bits then get the new c and new x |
|---|
| 133 | | from the the top and bottom halves. |
|---|
| 134 | | But if 'a' has a special form, for example, |
|---|
| 135 | | a=2^62+2^47+2 and b=2^64-1, then the new c and |
|---|
| 136 | | the new x can be formed with shifts, tests and +/-'s, |
|---|
| 137 | | again with a little fiddling because b=2^64-1 rather |
|---|
| 138 | | than 2^64. (The latter is not an optimal choice because, |
|---|
| 139 | | being a square, it cannot be a primitive root of the |
|---|
| 140 | | prime a*b^k+1, where 'k' is the 'lag': |
|---|
| 141 | | x(n)=a*x(n-k)+carry mod b.) |
|---|
| 142 | | But the multiplier a=2^62+2^47+2 makes a*b^4+1 a prime for |
|---|
| 143 | | which b=2^64-1 is a primitive root, and getting the new x and |
|---|
| 144 | | new c can be done with arithmetic on integers the size of x. |
|---|
| 145 | | */ |
|---|
| 146 | | |
|---|
| 147 | | struct RndCtx |
|---|
| 148 | | { |
|---|
| 149 | | uint64_t x; |
|---|
| 150 | | uint64_t y; |
|---|
| 151 | | uint64_t z; |
|---|
| 152 | | uint64_t w; |
|---|
| 153 | | uint64_t c; |
|---|
| 154 | | uint32_t u32x; |
|---|
| 155 | | uint32_t u32y; |
|---|
| 156 | | }; |
|---|
| 157 | | typedef struct RndCtx RNDCTX; |
|---|
| 158 | | typedef RNDCTX *PRNDCTX; |
|---|
| 159 | | |
|---|
| 160 | | /** |
|---|
| 161 | | * Initialize seeds. |
|---|
| 162 | | * |
|---|
| 163 | | * @remarks You should choose ANY 4 random 64-bit |
|---|
| 164 | | * seeds x,y,z,w < 2^64-1 and a random seed c in |
|---|
| 165 | | * 0<= c < a = 2^62+2^47+2. |
|---|
| 166 | | * There are P=(2^62+2^46+2)*(2^64-1)^4 > 2^318 possible choices |
|---|
| 167 | | * for seeds, the period of the RNG. |
|---|
| 168 | | */ |
|---|
| 169 | | RTDECL(int) RTPRandInit(PRNDCTX pCtx, uint32_t u32Seed) |
|---|
| 170 | | { |
|---|
| 171 | | if (u32Seed == 0) |
|---|
| 172 | | u32Seed = (uint32_t)(ASMReadTSC() >> 8); |
|---|
| 173 | | /* Zero is not a good seed. */ |
|---|
| 174 | | if (u32Seed == 0) |
|---|
| 175 | | u32Seed = 362436069; |
|---|
| 176 | | pCtx->x = u32Seed; |
|---|
| 177 | | pCtx->y = 17280675555674358941ULL; |
|---|
| 178 | | pCtx->z = 6376492577913983186ULL; |
|---|
| 179 | | pCtx->w = 9064188857900113776ULL; |
|---|
| 180 | | pCtx->c = 123456789; |
|---|
| 181 | | pCtx->u32x = 2282008; |
|---|
| 182 | | pCtx->u32y = u32Seed; |
|---|
| 183 | | return VINF_SUCCESS; |
|---|
| 184 | | } |
|---|
| 185 | | |
|---|
| 186 | | RTDECL(uint32_t) RTPRandGetSeedInfo(PRNDCTX pCtx) |
|---|
| 187 | | { |
|---|
| 188 | | return pCtx->u32y; |
|---|
| 189 | | } |
|---|
| 190 | | |
|---|
| 191 | | /** |
|---|
| 192 | | * Generate a 64-bit unsigned random number. |
|---|
| 193 | | * |
|---|
| 194 | | * @returns The pseudo random number. |
|---|
| 195 | | */ |
|---|
| 196 | | RTDECL(uint64_t) RTPRandU64(PRNDCTX pCtx) |
|---|
| 197 | | { |
|---|
| 198 | | uint64_t t; |
|---|
| 199 | | t = (pCtx->x<<47) + (pCtx->x<<62) + (pCtx->x<<1); |
|---|
| 200 | | t += pCtx->c; t+= (t < pCtx->c); |
|---|
| 201 | | pCtx->c = (t<pCtx->c) + (pCtx->x>>17) + (pCtx->x>>2) + (pCtx->x>>63); |
|---|
| 202 | | pCtx->x = pCtx->y; pCtx->y = pCtx->z ; pCtx->z = pCtx->w; |
|---|
| 203 | | return (pCtx->w = ~(t + pCtx->c)-1); |
|---|
| 204 | | } |
|---|
| 205 | | |
|---|
| 206 | | /** |
|---|
| 207 | | * Generate a 64-bit unsigned pseudo random number in the set |
|---|
| 208 | | * [u64First..u64Last]. |
|---|
| 209 | | * |
|---|
| 210 | | * @returns The pseudo random number. |
|---|
| 211 | | * @param u64First First number in the set. |
|---|
| 212 | | * @param u64Last Last number in the set. |
|---|
| 213 | | */ |
|---|
| 214 | | RTDECL(uint64_t) RTPRandU64Ex(PRNDCTX pCtx, uint64_t u64First, uint64_t u64Last) |
|---|
| 215 | | { |
|---|
| 216 | | if (u64First == 0 && u64Last == UINT64_MAX) |
|---|
| 217 | | return RTPRandU64(pCtx); |
|---|
| 218 | | |
|---|
| 219 | | uint64_t u64Tmp; |
|---|
| 220 | | uint64_t u64Range = u64Last - u64First + 1; |
|---|
| 221 | | uint64_t u64Scale = UINT64_MAX / u64Range; |
|---|
| 222 | | |
|---|
| 223 | | do |
|---|
| | 58 | for (unsigned i=0; i < cEntries; i++) |
|---|
| 225 | | u64Tmp = RTPRandU64(pCtx) / u64Scale; |
|---|
| 226 | | } while (u64Tmp >= u64Range); |
|---|
| 227 | | return u64First + u64Tmp; |
|---|
| 228 | | } |
|---|
| 229 | | |
|---|
| 230 | | /** |
|---|
| 231 | | * Generate a 32-bit unsigned random number. |
|---|
| 232 | | * |
|---|
| 233 | | * @returns The pseudo random number. |
|---|
| 234 | | */ |
|---|
| 235 | | RTDECL(uint32_t) RTPRandU32(PRNDCTX pCtx) |
|---|
| 236 | | { |
|---|
| 237 | | return ( pCtx->u32x = 69069 * pCtx->u32x + 123, |
|---|
| 238 | | pCtx->u32y ^= pCtx->u32y<<13, |
|---|
| 239 | | pCtx->u32y ^= pCtx->u32y>>17, |
|---|
| 240 | | pCtx->u32y ^= pCtx->u32y<<5, |
|---|
| 241 | | pCtx->u32x + pCtx->u32y ); |
|---|
| 242 | | } |
|---|
| 243 | | |
|---|
| 244 | | /** |
|---|
| 245 | | * Generate a 32-bit unsigned pseudo random number in the set |
|---|
| 246 | | * [u32First..u32Last]. |
|---|
| 247 | | * |
|---|
| 248 | | * @returns The pseudo random number. |
|---|
| 249 | | * @param u32First First number in the set. |
|---|
| 250 | | * @param u32Last Last number in the set. |
|---|
| 251 | | */ |
|---|
| 252 | | RTDECL(uint32_t) RTPRandU32Ex(PRNDCTX pCtx, uint32_t u32First, uint32_t u32Last) |
|---|
| 253 | | { |
|---|
| 254 | | if (u32First == 0 && u32Last == UINT32_MAX) |
|---|
| 255 | | return RTPRandU32(pCtx); |
|---|
| 256 | | |
|---|
| 257 | | uint32_t u32Tmp; |
|---|
| 258 | | uint32_t u32Range = u32Last - u32First + 1; |
|---|
| 259 | | uint32_t u32Scale = UINT32_MAX / u32Range; |
|---|
| 260 | | |
|---|
| 261 | | do |
|---|
| 262 | | { |
|---|
| 263 | | u32Tmp = RTPRandU32(pCtx) / u32Scale; |
|---|
| 264 | | } while (u32Tmp >= u32Range); |
|---|
| 265 | | return u32First + u32Tmp; |
|---|
| 266 | | } |
|---|
| 267 | | |
|---|
| 268 | | /* End of IPRT code */ |
|---|
| 269 | | |
|---|
| 270 | | struct Segment |
|---|
| 271 | | { |
|---|
| 272 | | uint64_t u64Offset; |
|---|
| 273 | | uint32_t u32Length; |
|---|
| 274 | | uint32_t u8Value; |
|---|
| 275 | | }; |
|---|
| 276 | | typedef struct Segment *PSEGMENT; |
|---|
| 277 | | |
|---|
| 278 | | static void initializeRandomGenerator(PRNDCTX pCtx, uint32_t u32Seed) |
|---|
| 279 | | { |
|---|
| 280 | | int rc = RTPRandInit(pCtx, u32Seed); |
|---|
| 281 | | if (VBOX_FAILURE(rc)) |
|---|
| 282 | | RTPrintf("ERROR: Failed to initialize random generator. RC=%Vrc\n", rc); |
|---|
| 283 | | else |
|---|
| 284 | | { |
|---|
| 285 | | RTPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx)); |
|---|
| 286 | | RTLogPrintf("INFO: Random generator seed used: %x\n", RTPRandGetSeedInfo(pCtx)); |
|---|
| 287 | | } |
|---|
| 288 | | } |
|---|
| 289 | | |
|---|
| 290 | | static int compareSegments(const void *left, const void *right) |
|---|
| 291 | | { |
|---|
| 292 | | /* Note that no duplicates are allowed in the array being sorted. */ |
|---|
| 293 | | return ((PSEGMENT)left)->u64Offset < ((PSEGMENT)right)->u64Offset ? -1 : 1; |
|---|
| 294 | | } |
|---|
| 295 | | |
|---|
| 296 | | 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) |
|---|
| 297 | | { |
|---|
| 298 | | uint32_t i; |
|---|
| 299 | | /* Generate segment offsets. */ |
|---|
| 300 | | for (i = 0; i < nSegments; i++) |
|---|
| 301 | | { |
|---|
| 302 | | bool fDuplicateFound; |
|---|
| 303 | | do |
|---|
| | 60 | RTPrintf("Backend %u: name=%s capabilities=%#06x extensions=", |
|---|
| | 61 | i, aVDInfo[i].pszBackend, aVDInfo[i].uBackendCaps); |
|---|
| | 62 | if (aVDInfo[i].papszFileExtensions) |
|---|
| 356 | | { |
|---|
| 357 | | *pMergeSegment = *pDiffSegment; |
|---|
| 358 | | if (pMergeSegment->u64Offset + pMergeSegment->u32Length <= pBaseSegment->u64Offset) |
|---|
| 359 | | { |
|---|
| 360 | | pDiffSegment++; |
|---|
| 361 | | pMergeSegment++; |
|---|
| 362 | | } |
|---|
| 363 | | else |
|---|
| 364 | | { |
|---|
| 365 | | if (pBaseSegment->u64Offset + pBaseSegment->u32Length > pDiffSegment->u64Offset + pDiffSegment->u32Length) |
|---|
| 366 | | { |
|---|
| 367 | | pBaseSegment->u32Length -= pDiffSegment->u64Offset + pDiffSegment->u32Length - pBaseSegment->u64Offset; |
|---|
| 368 | | Assert(pBaseSegment->u32Length <= u32MaxLength); |
|---|
| 369 | | pBaseSegment->u64Offset = pDiffSegment->u64Offset + pDiffSegment->u32Length; |
|---|
| 370 | | pDiffSegment++; |
|---|
| 371 | | pMergeSegment++; |
|---|
| 372 | | } |
|---|
| 373 | | else |
|---|
| 374 | | pBaseSegment++; |
|---|
| 375 | | } |
|---|
| 376 | | } |
|---|
| 377 | | } |
|---|
| 378 | | } |
|---|
| 379 | | |
|---|
| 380 | | static void writeSegmentsToDisk(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment) |
|---|
| 381 | | { |
|---|
| 382 | | while (pSegment->u32Length) |
|---|
| 383 | | { |
|---|
| 384 | | //memset((uint8_t*)pvBuf + pSegment->u64Offset, pSegment->u8Value, pSegment->u32Length); |
|---|
| 385 | | memset(pvBuf, pSegment->u8Value, pSegment->u32Length); |
|---|
| 386 | | VDWrite(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length); |
|---|
| 387 | | pSegment++; |
|---|
| 388 | | } |
|---|
| 389 | | } |
|---|
| 390 | | |
|---|
| 391 | | static int readAndCompareSegments(PVBOXHDD pVD, void *pvBuf, PSEGMENT pSegment) |
|---|
| 392 | | { |
|---|
| 393 | | while (pSegment->u32Length) |
|---|
| 394 | | { |
|---|
| 395 | | int rc = VDRead(pVD, pSegment->u64Offset, pvBuf, pSegment->u32Length); |
|---|
| 396 | | if (VBOX_FAILURE(rc)) |
|---|
| 397 | | { |
|---|
| 398 | | RTPrintf("ERROR: Failed to read from virtual disk\n"); |
|---|
| 399 | | return rc; |
|---|
| 400 | | } |
|---|
| 401 | | else |
|---|
| 402 | | { |
|---|
| 403 | | for (unsigned i = 0; i < pSegment->u32Length; i++) |
|---|
| 404 | | if (((uint8_t*)pvBuf)[i] != pSegment->u8Value) |
|---|
| 405 | | { |
|---|
| 406 | | RTPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n", |
|---|
| 407 | | pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i], |
|---|
| 408 | | pSegment->u8Value); |
|---|
| 409 | | RTLogPrintf("ERROR: Segment at %Lx of %x bytes is corrupt at offset %x (found %x instead of %x)\n", |
|---|
| 410 | | pSegment->u64Offset, pSegment->u32Length, i, ((uint8_t*)pvBuf)[i], |
|---|
| 411 | | pSegment->u8Value); |
|---|
| 412 | | return VERR_INTERNAL_ERROR; |
|---|
| 413 | | } |
|---|
| 414 | | } |
|---|
| 415 | | pSegment++; |
|---|
| | 77 | RTPrintf("<NONE>\n"); |
|---|
| 418 | | return VINF_SUCCESS; |
|---|
| 419 | | } |
|---|
| 420 | | |
|---|
| 421 | | static int tstVDOpenCreateWriteMerge(const char *pszBackend, |
|---|
| 422 | | const char *pszBaseFilename, |
|---|
| 423 | | const char *pszDiffFilename, |
|---|
| 424 | | uint32_t u32Seed) |
|---|
| 425 | | { |
|---|
| 426 | | int rc; |
|---|
| 427 | | PVBOXHDD pVD = NULL; |
|---|
| 428 | | char *pszFormat; |
|---|
| 429 | | PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 }; |
|---|
| 430 | | PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 }; |
|---|
| 431 | | uint64_t u64DiskSize = 1000 * _1M; |
|---|
| 432 | | uint32_t u32SectorSize = 512; |
|---|
| 433 | | VDINTERFACE VDIError; |
|---|
| 434 | | VDINTERFACEERROR VDIErrorCallbacks; |
|---|
| 435 | | |
|---|
| 436 | | #define CHECK(str) \ |
|---|
| 437 | | do \ |
|---|
| 438 | | { \ |
|---|
| 439 | | RTPrintf("%s rc=%Vrc\n", str, rc); \ |
|---|
| 440 | | if (VBOX_FAILURE(rc)) \ |
|---|
| 441 | | { \ |
|---|
| 442 | | VDCloseAll(pVD); \ |
|---|
| 443 | | return rc; \ |
|---|
| 444 | | } \ |
|---|
| 445 | | } while (0) |
|---|
| 446 | | |
|---|
| 447 | | /* Create error interface. */ |
|---|
| 448 | | VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR); |
|---|
| 449 | | VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR; |
|---|
| 450 | | VDIErrorCallbacks.pfnError = tstVDError; |
|---|
| 451 | | |
|---|
| 452 | | rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks, |
|---|
| 453 | | NULL, NULL); |
|---|
| 454 | | AssertRC(rc); |
|---|
| 455 | | |
|---|
| 456 | | |
|---|
| 457 | | rc = VDCreate(&VDIError, &pVD); |
|---|
| 458 | | CHECK("VDCreate()"); |
|---|
| 459 | | |
|---|
| 460 | | RTFILE File; |
|---|
| 461 | | rc = RTFileOpen(&File, pszBaseFilename, RTFILE_O_READ); |
|---|
| 462 | | if (VBOX_SUCCESS(rc)) |
|---|
| 463 | | { |
|---|
| 464 | | RTFileClose(File); |
|---|
| 465 | | rc = VDGetFormat(pszBaseFilename, &pszFormat); |
|---|
| 466 | | RTPrintf("VDGetFormat() pszFormat=%s rc=%Vrc\n", pszFormat, rc); |
|---|
| 467 | | if (VBOX_SUCCESS(rc) && strcmp(pszFormat, pszBackend)) |
|---|
| 468 | | { |
|---|
| 469 | | rc = VERR_GENERAL_FAILURE; |
|---|
| 470 | | RTPrintf("VDGetFormat() returned incorrect backend name\n"); |
|---|
| 471 | | } |
|---|
| 472 | | RTStrFree(pszFormat); |
|---|
| 473 | | CHECK("VDGetFormat()"); |
|---|
| 474 | | |
|---|
| 475 | | rc = VDOpen(pVD, pszBackend, pszBaseFilename, VD_OPEN_FLAGS_NORMAL); |
|---|
| 476 | | CHECK("VDOpen()"); |
|---|
| 477 | | } |
|---|
| 478 | | else |
|---|
| 479 | | { |
|---|
| 480 | | rc = VDCreateBase(pVD, pszBackend, pszBaseFilename, |
|---|
| 481 | | VD_IMAGE_TYPE_NORMAL, u64DiskSize, |
|---|
| 482 | | VD_IMAGE_FLAGS_NONE, "Test image", |
|---|
| 483 | | &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL, |
|---|
| 484 | | NULL, NULL); |
|---|
| 485 | | CHECK("VDCreateBase()"); |
|---|
| 486 | | } |
|---|
| 487 | | |
|---|
| 488 | | int nSegments = 100; |
|---|
| 489 | | /* Allocate one extra element for a sentinel. */ |
|---|
| 490 | | PSEGMENT paBaseSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1)); |
|---|
| 491 | | PSEGMENT paDiffSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1)); |
|---|
| 492 | | PSEGMENT paMergeSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1) * 3); |
|---|
| 493 | | |
|---|
| 494 | | void *pvBuf = RTMemAlloc(_1M); |
|---|
| 495 | | |
|---|
| 496 | | RNDCTX ctx; |
|---|
| 497 | | initializeRandomGenerator(&ctx, u32Seed); |
|---|
| 498 | | generateRandomSegments(&ctx, paBaseSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u); |
|---|
| 499 | | generateRandomSegments(&ctx, paDiffSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 128u, 255u); |
|---|
| 500 | | |
|---|
| 501 | | /*PSEGMENT pSegment; |
|---|
| 502 | | RTPrintf("Base segments:\n"); |
|---|
| 503 | | for (pSegment = paBaseSegments; pSegment->u32Length; pSegment++) |
|---|
| 504 | | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/ |
|---|
| 505 | | writeSegmentsToDisk(pVD, pvBuf, paBaseSegments); |
|---|
| 506 | | |
|---|
| 507 | | rc = VDCreateDiff(pVD, pszBackend, pszDiffFilename, |
|---|
| 508 | | VD_IMAGE_FLAGS_NONE, "Test diff image", NULL, |
|---|
| 509 | | VD_OPEN_FLAGS_NORMAL, NULL, NULL); |
|---|
| 510 | | CHECK("VDCreateDiff()"); |
|---|
| 511 | | |
|---|
| 512 | | /*RTPrintf("\nDiff segments:\n"); |
|---|
| 513 | | for (pSegment = paDiffSegments; pSegment->u32Length; pSegment++) |
|---|
| 514 | | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/ |
|---|
| 515 | | writeSegmentsToDisk(pVD, pvBuf, paDiffSegments); |
|---|
| 516 | | |
|---|
| 517 | | VDDumpImages(pVD); |
|---|
| 518 | | |
|---|
| 519 | | RTPrintf("Merging diff into base..\n"); |
|---|
| 520 | | rc = VDMerge(pVD, (unsigned)-1, 0, NULL, NULL); |
|---|
| 521 | | CHECK("VDMerge()"); |
|---|
| 522 | | |
|---|
| 523 | | mergeSegments(paBaseSegments, paDiffSegments, paMergeSegments, _1M); |
|---|
| 524 | | /*RTPrintf("\nMerged segments:\n"); |
|---|
| 525 | | for (pSegment = paMergeSegments; pSegment->u32Length; pSegment++) |
|---|
| 526 | | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/ |
|---|
| 527 | | rc = readAndCompareSegments(pVD, pvBuf, paMergeSegments); |
|---|
| 528 | | CHECK("readAndCompareSegments()"); |
|---|
| 529 | | |
|---|
| 530 | | RTMemFree(paMergeSegments); |
|---|
| 531 | | RTMemFree(paDiffSegments); |
|---|
| 532 | | RTMemFree(paBaseSegments); |
|---|
| 533 | | |
|---|
| 534 | | VDDumpImages(pVD); |
|---|
| 535 | | |
|---|
| 536 | | VDCloseAll(pVD); |
|---|
| 537 | | #undef CHECK |
|---|
| 538 | | return 0; |
|---|
| 539 | | } |
|---|
| 540 | | |
|---|
| 541 | | static int tstVDCreateWriteOpenRead(const char *pszBackend, |
|---|
| 542 | | const char *pszFilename, |
|---|
| 543 | | uint32_t u32Seed) |
|---|
| 544 | | { |
|---|
| 545 | | int rc; |
|---|
| 546 | | PVBOXHDD pVD = NULL; |
|---|
| 547 | | PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 }; |
|---|
| 548 | | PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 }; |
|---|
| 549 | | uint64_t u64DiskSize = 1000 * _1M; |
|---|
| 550 | | uint32_t u32SectorSize = 512; |
|---|
| 551 | | VDINTERFACE VDIError; |
|---|
| 552 | | VDINTERFACEERROR VDIErrorCallbacks; |
|---|
| 553 | | |
|---|
| 554 | | #define CHECK(str) \ |
|---|
| 555 | | do \ |
|---|
| 556 | | { \ |
|---|
| 557 | | RTPrintf("%s rc=%Vrc\n", str, rc); \ |
|---|
| 558 | | if (VBOX_FAILURE(rc)) \ |
|---|
| 559 | | { \ |
|---|
| 560 | | VDCloseAll(pVD); \ |
|---|
| 561 | | return rc; \ |
|---|
| 562 | | } \ |
|---|
| 563 | | } while (0) |
|---|
| 564 | | |
|---|
| 565 | | /* Create error interface. */ |
|---|
| 566 | | VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR); |
|---|
| 567 | | VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR; |
|---|
| 568 | | VDIErrorCallbacks.pfnError = tstVDError; |
|---|
| 569 | | |
|---|
| 570 | | rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks, |
|---|
| 571 | | NULL, NULL); |
|---|
| 572 | | AssertRC(rc); |
|---|
| 573 | | |
|---|
| 574 | | |
|---|
| 575 | | rc = VDCreate(&VDIError, &pVD); |
|---|
| 576 | | CHECK("VDCreate()"); |
|---|
| 577 | | |
|---|
| 578 | | RTFILE File; |
|---|
| 579 | | rc = RTFileOpen(&File, pszFilename, RTFILE_O_READ); |
|---|
| 580 | | if (VBOX_SUCCESS(rc)) |
|---|
| 581 | | { |
|---|
| 582 | | RTFileClose(File); |
|---|
| 583 | | RTFileDelete(pszFilename); |
|---|
| 584 | | } |
|---|
| 585 | | |
|---|
| 586 | | rc = VDCreateBase(pVD, pszBackend, pszFilename, |
|---|
| 587 | | VD_IMAGE_TYPE_NORMAL, u64DiskSize, |
|---|
| 588 | | VD_IMAGE_FLAGS_NONE, "Test image", |
|---|
| 589 | | &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL, |
|---|
| 590 | | NULL, NULL); |
|---|
| 591 | | CHECK("VDCreateBase()"); |
|---|
| 592 | | |
|---|
| 593 | | int nSegments = 100; |
|---|
| 594 | | /* Allocate one extra element for a sentinel. */ |
|---|
| 595 | | PSEGMENT paSegments = (PSEGMENT)RTMemAllocZ(sizeof(struct Segment) * (nSegments + 1)); |
|---|
| 596 | | |
|---|
| 597 | | void *pvBuf = RTMemAlloc(_1M); |
|---|
| 598 | | |
|---|
| 599 | | RNDCTX ctx; |
|---|
| 600 | | initializeRandomGenerator(&ctx, u32Seed); |
|---|
| 601 | | generateRandomSegments(&ctx, paSegments, nSegments, _1M, u64DiskSize, u32SectorSize, 0u, 127u); |
|---|
| 602 | | /*for (PSEGMENT pSegment = paSegments; pSegment->u32Length; pSegment++) |
|---|
| 603 | | RTPrintf("off: %08Lx len: %05x val: %02x\n", pSegment->u64Offset, pSegment->u32Length, pSegment->u8Value);*/ |
|---|
| 604 | | |
|---|
| 605 | | writeSegmentsToDisk(pVD, pvBuf, paSegments); |
|---|
| 606 | | |
|---|
| 607 | | VDCloseAll(pVD); |
|---|
| 608 | | |
|---|
| 609 | | rc = VDOpen(pVD, pszBackend, pszFilename, VD_OPEN_FLAGS_NORMAL); |
|---|
| 610 | | CHECK("VDOpen()"); |
|---|
| 611 | | rc = readAndCompareSegments(pVD, pvBuf, paSegments); |
|---|
| 612 | | CHECK("readAndCompareSegments()"); |
|---|
| 613 | | |
|---|
| 614 | | RTMemFree(paSegments); |
|---|
| 615 | | |
|---|
| 616 | | VDCloseAll(pVD); |
|---|
| 660 | | rc = tstVDCreateDelete("VDI", "tmpVDCreate.vdi", 2 * _4G, |
|---|
| 661 | | VD_IMAGE_TYPE_FIXED, VD_IMAGE_FLAGS_NONE, |
|---|
| 662 | | true); |
|---|
| 663 | | if (VBOX_FAILURE(rc)) |
|---|
| 664 | | { |
|---|
| 665 | | RTPrintf("tstVD: fixed VDI create test failed! rc=%Vrc\n", rc); |
|---|
| 666 | | g_cErrors++; |
|---|
| 667 | | } |
|---|
| 668 | | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G, |
|---|
| 669 | | VD_IMAGE_TYPE_NORMAL, VD_IMAGE_FLAGS_NONE, |
|---|
| 670 | | true); |
|---|
| 671 | | if (VBOX_FAILURE(rc)) |
|---|
| 672 | | { |
|---|
| 673 | | RTPrintf("tstVD: dynamic VMDK create test failed! rc=%Vrc\n", rc); |
|---|
| 674 | | g_cErrors++; |
|---|
| 675 | | } |
|---|
| 676 | | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G, |
|---|
| 677 | | VD_IMAGE_TYPE_NORMAL, VD_VMDK_IMAGE_FLAGS_SPLIT_2G, |
|---|
| 678 | | true); |
|---|
| 679 | | if (VBOX_FAILURE(rc)) |
|---|
| 680 | | { |
|---|
| 681 | | RTPrintf("tstVD: dynamic split VMDK create test failed! rc=%Vrc\n", rc); |
|---|
| 682 | | g_cErrors++; |
|---|
| 683 | | } |
|---|
| 684 | | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G, |
|---|
| 685 | | VD_IMAGE_TYPE_FIXED, VD_IMAGE_FLAGS_NONE, |
|---|
| 686 | | true); |
|---|
| 687 | | if (VBOX_FAILURE(rc)) |
|---|
| 688 | | { |
|---|
| 689 | | RTPrintf("tstVD: fixed VMDK create test failed! rc=%Vrc\n", rc); |
|---|
| 690 | | g_cErrors++; |
|---|
| 691 | | } |
|---|
| 692 | | rc = tstVDCreateDelete("VMDK", "tmpVDCreate.vmdk", 2 * _4G, |
|---|
| 693 | | VD_IMAGE_TYPE_FIXED, VD_VMDK_IMAGE_FLAGS_SPLIT_2G, |
|---|
| 694 | | true); |
|---|
| 695 | | if (VBOX_FAILURE(rc)) |
|---|
| 696 | | { |
|---|
| 697 | | RTPrintf("tstVD: fixed split VMDK create test failed! rc=%Vrc\n", rc); |
|---|
| 698 | | g_cErrors++; |
|---|
| 699 | | } |
|---|
| 700 | | rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G, |
|---|
| 701 | | VD_IMAGE_TYPE_NORMAL, VD_IMAGE_FLAGS_NONE, |
|---|
| 702 | | true); |
|---|
| 703 | | if (VBOX_FAILURE(rc)) |
|---|
| 704 | | { |
|---|
| 705 | | RTPrintf("tstVD: dynamic VHD create test failed! rc=%Vrc\n", rc); |
|---|
| 706 | | g_cErrors++; |
|---|
| 707 | | } |
|---|
| 708 | | rc = tstVDCreateDelete("VHD", "tmpVDCreate.vhd", 2 * _4G, |
|---|
| 709 | | VD_IMAGE_TYPE_FIXED, VD_IMAGE_FLAGS_NONE, |
|---|
| 710 | | true); |
|---|
| 711 | | if (VBOX_FAILURE(rc)) |
|---|
| 712 | | { |
|---|
| 713 | | RTPrintf("tstVD: fixed VHD create test failed! rc=%Vrc\n", rc); |
|---|
| 714 | | g_cErrors++; |
|---|
| 715 | | } |
|---|
| 716 | | |
|---|
| 717 | | rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed); |
|---|
| 718 | | if (VBOX_FAILURE(rc)) |
|---|
| 719 | | { |
|---|
| 720 | | RTPrintf("tstVD: VDI test failed (new image)! rc=%Vrc\n", rc); |
|---|
| 721 | | g_cErrors++; |
|---|
| 722 | | } |
|---|
| 723 | | rc = tstVDOpenCreateWriteMerge("VDI", "tmpVDBase.vdi", "tmpVDDiff.vdi", u32Seed); |
|---|
| 724 | | if (VBOX_FAILURE(rc)) |
|---|
| 725 | | { |
|---|
| 726 | | RTPrintf("tstVD: VDI test failed (existing image)! rc=%Vrc\n", rc); |
|---|
| 727 | | g_cErrors++; |
|---|
| 728 | | } |
|---|
| 729 | | rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed); |
|---|
| 730 | | if (VBOX_FAILURE(rc)) |
|---|
| 731 | | { |
|---|
| 732 | | RTPrintf("tstVD: VMDK test failed (new image)! rc=%Vrc\n", rc); |
|---|
| 733 | | g_cErrors++; |
|---|
| 734 | | } |
|---|
| 735 | | rc = tstVDOpenCreateWriteMerge("VMDK", "tmpVDBase.vmdk", "tmpVDDiff.vmdk", u32Seed); |
|---|
| 736 | | if (VBOX_FAILURE(rc)) |
|---|
| 737 | | { |
|---|
| 738 | | RTPrintf("tstVD: VMDK test failed (existing image)! rc=%Vrc\n", rc); |
|---|
| 739 | | g_cErrors++; |
|---|
| 740 | | } |
|---|
| 741 | | #endif |
|---|
| 742 | | |
|---|
| 743 | | rc = tstVDCreateWriteOpenRead("VHD", "tmpVDCreate.vhd", u32Seed); |
|---|
| 744 | | if (VBOX_FAILURE(rc)) |
|---|
| 745 | | { |
|---|
| 746 | | RTPrintf("tstVD: VHD test failed (creating image)! rc=%Vrc\n", rc); |
|---|
| 747 | | g_cErrors++; |
|---|
| 748 | | } |
|---|
| 749 | | |
|---|
| 750 | | rc = tstVDOpenCreateWriteMerge("VHD", "tmpVDBase.vhd", "tmpVDDiff.vhd", u32Seed); |
|---|
| 751 | | if (VBOX_FAILURE(rc)) |
|---|
| 752 | | { |
|---|
| 753 | | RTPrintf("tstVD: VHD test failed (existing image)! rc=%Vrc\n", rc); |
|---|
| 754 | | g_cErrors++; |
|---|
| 755 | | } |
|---|
| 756 | | |
|---|
| 757 | | /* |
|---|
| 758 | | * Clean up any leftovers. |
|---|
| 759 | | */ |
|---|
| 760 | | RTFileDelete("tmpVDCreate.vdi"); |
|---|
| 761 | | RTFileDelete("tmpVDCreate.vmdk"); |
|---|
| 762 | | RTFileDelete("tmpVDCreate.vhd"); |
|---|
| 763 | | RTFileDelete("tmpVDBase.vdi"); |
|---|
| 764 | | RTFileDelete("tmpVDDiff.vdi"); |
|---|
| 765 | | RTFileDelete("tmpVDBase.vmdk"); |
|---|
| 766 | | RTFileDelete("tmpVDDiff.vmdk"); |
|---|
| 767 | | RTFileDelete("tmpVDBase.vhd"); |
|---|
| 768 | | RTFileDelete("tmpVDDiff.vhd"); |
|---|