Ejemplo n.º 1
0
static int tstVDCreateShareDelete(const char *pszBackend, const char *pszFilename,
                                  uint64_t cbSize, unsigned uFlags)
{
    int rc;
    PVBOXHDD pVD = NULL, pVD2 = NULL;
    VDGEOMETRY       PCHS = { 0, 0, 0 };
    VDGEOMETRY       LCHS = { 0, 0, 0 };
    PVDINTERFACE     pVDIfs = NULL;
    VDINTERFACEERROR VDIfError;

#define CHECK(str) \
    do \
    { \
        RTPrintf("%s rc=%Rrc\n", str, rc); \
        if (RT_FAILURE(rc)) \
        { \
            VDDestroy(pVD); \
            return rc; \
        } \
    } while (0)

    /* Create error interface. */
    VDIfError.pfnError = tstVDError;
    VDIfError.pfnMessage = tstVDMessage;

    rc = VDInterfaceAdd(&VDIfError.Core, "tstVD_Error", VDINTERFACETYPE_ERROR,
                        NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
    AssertRC(rc);

    rc = VDCreate(pVDIfs, VDTYPE_HDD, &pVD);
    CHECK("VDCreate()");
    rc = VDCreate(pVDIfs, VDTYPE_HDD, &pVD2);
    CHECK("VDCreate() #2");

    rc = VDCreateBase(pVD, pszBackend, pszFilename, cbSize,
                      uFlags, "Test image", &PCHS, &LCHS, NULL,
                      VD_OPEN_FLAGS_NORMAL, NULL, NULL);
    CHECK("VDCreateBase()");

    VDClose(pVD, false);

    rc = VDOpen(pVD, pszBackend, pszFilename, VD_OPEN_FLAGS_SHAREABLE, NULL);
    CHECK("VDOpen()");
    rc = VDOpen(pVD2, pszBackend, pszFilename, VD_OPEN_FLAGS_SHAREABLE, NULL);
    CHECK("VDOpen() #2");
    if (VDIsReadOnly(pVD2))
        rc = VERR_VD_IMAGE_READ_ONLY;

    VDClose(pVD2, false);
    VDClose(pVD, true);

    VDDestroy(pVD);
    VDDestroy(pVD2);
#undef CHECK
    return 0;
}
static int tstVDOpenCreateWriteMerge(PVDSNAPTEST pTest)
{
    int rc;
    PVBOXHDD pVD = NULL;
    VDGEOMETRY       PCHS = { 0, 0, 0 };
    VDGEOMETRY       LCHS = { 0, 0, 0 };
    PVDINTERFACE     pVDIfs = NULL;
    VDINTERFACEERROR VDIfError;

    /** Buffer storing the random test pattern. */
    uint8_t *pbTestPattern = NULL;
    /** Number of disk segments */
    uint32_t cDiskSegments;
    /** Array of disk segments */
    PVDDISKSEG paDiskSeg = NULL;
    unsigned   cDiffs = 0;
    unsigned   idDiff = 0; /* Diff ID counter for the filename */

    /* Delete all images from a previous run. */
    RTFileDelete(pTest->pcszBaseImage);
    for (unsigned i = 0; i < pTest->cIterations; i++)
    {
        char *pszDiffFilename = NULL;

        rc = RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", i, pTest->pcszDiffSuff);
        if (RT_SUCCESS(rc))
        {
            if (RTFileExists(pszDiffFilename))
                RTFileDelete(pszDiffFilename);
            RTStrFree(pszDiffFilename);
        }
    }

    /* Create the virtual disk test data */
    pbTestPattern = (uint8_t *)RTMemAlloc(pTest->cbTestPattern);

    RTRandAdvBytes(g_hRand, pbTestPattern, pTest->cbTestPattern);
    cDiskSegments = RTRandAdvU32Ex(g_hRand, pTest->cDiskSegsMin, pTest->cDiskSegsMax);

    uint64_t cbDisk = 0;

    paDiskSeg = (PVDDISKSEG)RTMemAllocZ(cDiskSegments * sizeof(VDDISKSEG));
    if (!paDiskSeg)
    {
        RTPrintf("Failed to allocate memory for random disk segments\n");
        g_cErrors++;
        return VERR_NO_MEMORY;
    }

    for (unsigned i = 0; i < cDiskSegments; i++)
    {
        paDiskSeg[i].off    = cbDisk;
        paDiskSeg[i].cbSeg  = RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 512, pTest->cbTestPattern), 512);
        if (tstVDSnapIsTrue(pTest->uAllocatedBlocks))
            paDiskSeg[i].pbData = pbTestPattern + RT_ALIGN_64(RTRandAdvU64Ex(g_hRand, 0, pTest->cbTestPattern - paDiskSeg[i].cbSeg - 512), 512);
        else
            paDiskSeg[i].pbData = NULL; /* Not allocated initially */
        cbDisk += paDiskSeg[i].cbSeg;
    }

    RTPrintf("Disk size is %llu bytes\n", cbDisk);

#define CHECK(str) \
    do \
    { \
        RTPrintf("%s rc=%Rrc\n", str, rc); \
        if (RT_FAILURE(rc)) \
        { \
            if (pbTestPattern) \
                RTMemFree(pbTestPattern); \
            if (paDiskSeg) \
                RTMemFree(paDiskSeg); \
            VDDestroy(pVD); \
            g_cErrors++; \
            return rc; \
        } \
    } while (0)

#define CHECK_BREAK(str) \
    do \
    { \
        RTPrintf("%s rc=%Rrc\n", str, rc); \
        if (RT_FAILURE(rc)) \
        { \
            g_cErrors++; \
            break; \
        } \
    } while (0)

    /* Create error interface. */
    /* Create error interface. */
    VDIfError.pfnError = tstVDError;
    VDIfError.pfnMessage = tstVDMessage;

    rc = VDInterfaceAdd(&VDIfError.Core, "tstVD_Error", VDINTERFACETYPE_ERROR,
                        NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
    AssertRC(rc);


    rc = VDCreate(pVDIfs, VDTYPE_HDD, &pVD);
    CHECK("VDCreate()");

    rc = VDCreateBase(pVD, pTest->pcszBackend, pTest->pcszBaseImage, cbDisk,
                      VD_IMAGE_FLAGS_NONE, "Test image",
                      &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL,
                      NULL, NULL);
    CHECK("VDCreateBase()");

    bool fInit = true;
    uint32_t cIteration = 0;

    /* Do the real work now */
    while (   RT_SUCCESS(rc)
           && cIteration < pTest->cIterations)
    {
        /* Write */
        rc = tstVDSnapWrite(pVD, paDiskSeg, cDiskSegments, cbDisk, fInit);
        CHECK_BREAK("tstVDSnapWrite()");

        fInit = false;

        /* Write returned, do we want to create a new diff or merge them? */
        bool fCreate =   cDiffs < pTest->cDiffsMinBeforeMerge
                       ? true
                       : tstVDSnapIsTrue(pTest->uCreateDiffChance);

        if (fCreate)
        {
            char *pszDiffFilename = NULL;

            RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", idDiff, pTest->pcszDiffSuff);
            CHECK("RTStrAPrintf()");
            idDiff++;
            cDiffs++;

            rc = VDCreateDiff(pVD, pTest->pcszBackend, pszDiffFilename,
                              VD_IMAGE_FLAGS_NONE, "Test diff image", NULL, NULL,
                              VD_OPEN_FLAGS_NORMAL, NULL, NULL);
            CHECK_BREAK("VDCreateDiff()");

            RTStrFree(pszDiffFilename);
            VDDumpImages(pVD);

            /* Change data */
            tstVDSnapSegmentsDice(pTest, paDiskSeg, cDiskSegments, pbTestPattern, pTest->cbTestPattern);
        }
        else
        {
            uint32_t uStartMerge = RTRandAdvU32Ex(g_hRand, 1, cDiffs - 1);
            uint32_t uEndMerge   = RTRandAdvU32Ex(g_hRand, uStartMerge + 1, cDiffs);
            RTPrintf("Merging %u diffs from %u to %u...\n",
                     uEndMerge - uStartMerge,
                     uStartMerge,
                     uEndMerge);
            if (pTest->fForward)
                rc = VDMerge(pVD, uStartMerge, uEndMerge, NULL);
            else
                rc = VDMerge(pVD, uEndMerge, uStartMerge, NULL);
            CHECK_BREAK("VDMerge()");

            cDiffs -= uEndMerge - uStartMerge;

            VDDumpImages(pVD);

            /* Go through the disk segments and reset pointers. */
            for (uint32_t i = 0; i < cDiskSegments; i++)
            {
                if (paDiskSeg[i].pbDataDiff)
                {
                    paDiskSeg[i].pbData     = paDiskSeg[i].pbDataDiff;
                    paDiskSeg[i].pbDataDiff = NULL;
                }
            }

            /* Now compare the result with our test pattern */
            rc = tstVDSnapReadVerify(pVD, paDiskSeg, cDiskSegments, cbDisk);
            CHECK_BREAK("tstVDSnapReadVerify()");
        }
        cIteration++;
    }

    VDDumpImages(pVD);

    VDDestroy(pVD);
    if (paDiskSeg)
        RTMemFree(paDiskSeg);
    if (pbTestPattern)
        RTMemFree(pbTestPattern);

    RTFileDelete(pTest->pcszBaseImage);
    for (unsigned i = 0; i < idDiff; i++)
    {
        char *pszDiffFilename = NULL;

        RTStrAPrintf(&pszDiffFilename, "tstVDSnapDiff%u.%s", i, pTest->pcszDiffSuff);
        RTFileDelete(pszDiffFilename);
        RTStrFree(pszDiffFilename);
    }
#undef CHECK
    return rc;
}