VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.3 KB
RevLine 
[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. */
57unsigned g_cErrors = 0;
[1]58
[7895]59
[57415]60static 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]69static 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]77static 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]133static 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/*
197A C version of a very very good 64-bit RNG is given below.
198You should be able to adapt it to your particular needs.
[9262]199
[11353]200It is based on the complimentary-multiple-with-carry
201sequence
202 x(n)=a*x(n-4)+carry mod 2^64-1,
203which works as follows:
204Assume a certain multiplier 'a' and a base 'b'.
205Given a current x value and a current carry 'c',
206form: t=a*x+c
207Then the new carry is c=floor(t/b)
208and the new x value is x = b-1-(t mod b).
[9262]209
210
[11353]211Ordinarily, for 32-bit mwc or cmwc sequences, the
212value t=a*x+c can be formed in 64 bits, then the new c
213is the top and the new x the bottom 32 bits (with a little
214fiddling when b=2^32-1 and cmwc rather than mwc.)
[9262]215
216
[11353]217To generate 64-bit x's, it is difficult to form
218t=a*x+c in 128 bits then get the new c and new x
[14303]219from the top and bottom halves.
[11353]220But if 'a' has a special form, for example,
221a=2^62+2^47+2 and b=2^64-1, then the new c and
222the new x can be formed with shifts, tests and +/-'s,
223again with a little fiddling because b=2^64-1 rather
224than 2^64. (The latter is not an optimal choice because,
225being a square, it cannot be a primitive root of the
226prime a*b^k+1, where 'k' is the 'lag':
227 x(n)=a*x(n-k)+carry mod b.)
228But the multiplier a=2^62+2^47+2 makes a*b^4+1 a prime for
229which b=2^64-1 is a primitive root, and getting the new x and
230new c can be done with arithmetic on integers the size of x.
231*/
[9262]232
233struct 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};
243typedef struct RndCtx RNDCTX;
244typedef 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]255RTDECL(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]276RTDECL(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 */
286RTDECL(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 */
304RTDECL(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 */
325RTDECL(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 */
342RTDECL(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
360struct Segment
361{
362 uint64_t u64Offset;
363 uint32_t u32Length;
364 uint32_t u8Value;
365};
366typedef struct Segment *PSEGMENT;
367
[9264]368static 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]380static 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
386static 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]420static 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]472static 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]483static 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
513static 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]638static 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]719static 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
759static 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
812static 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]862int 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
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use