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;
}
Exemple #2
0
int
main (int argc, char **argv)
{
	char *diskType = "auto";
	char *imagefilename = NULL;
	char *mountpoint = NULL;
	int debug = 0;
	int foreground = 0;
	char c;
	int i;
	char *differencing[DIFFERENCING_MAX];
	int differencingLen = 0;

	extern char *optarg;
	extern int optind, optopt;

//
// *** Parse the command line options ***
//
	processName = argv[0];

	while ((c = getopt (argc, argv, GETOPT_ARGS)) != -1)
	{
		switch (c)
		{
			case 'r':
				readonly = 1;
				break;
			case 'g':
				foreground = 1;
				break;
			case 'v':
				verbose = 1;
				break;
			case 'a':
				allowall = 1;
				break;
			case 'w':
				allowall = 1;
				allowallw = 1;
				break;
			case 't':
				diskType = (char *) optarg;
				break;									// ignored if OLDAPI
			case 's':
				if (differencingLen == DIFFERENCING_MAX)
					usageAndExit ("Too many differencing disks");
				differencing[differencingLen++] = (char *) optarg;
				break;
			case 'f':
				imagefilename = (char *) optarg;
				break;
			case 'd':
				foreground = 1;
				debug = 1;
				break;
			case 'h':
				usageAndExit (NULL);
			case '?':
				usageAndExit ("Unknown option");
		}
	}
//
// *** Validate the command line ***
//
	if (argc != optind + 1)
		usageAndExit ("a single mountpoint must be specified");
	mountpoint = argv[optind];
	if (!mountpoint)
		usageAndExit ("no mountpoint specified");
	if (!imagefilename)
		usageAndExit ("no image chosen");
	if (stat (imagefilename, &VDfile_stat) < 0)
		usageAndExit ("cannot access imagefile");
	if (access (imagefilename, F_OK | R_OK | ((!readonly) ? W_OK : 0)) < 0)
		usageAndExit ("cannot access imagefile");
	for (i = 0; i < differencingLen; i++)
		if (access (differencing[i], F_OK | R_OK | ((readonly) ? 0 : W_OK)) < 0)
			usageAndExit ("cannot access differencing imagefile %s",
										differencing[i]);

#define IS_TYPE(s) (strcmp (s, diskType) == 0)
	if (!
			(IS_TYPE ("auto") || IS_TYPE ("VDI") || IS_TYPE ("VMDK")
			 || IS_TYPE ("VHD") || IS_TYPE ("auto")))
		usageAndExit ("invalid disk type specified");
	if (strcmp ("auto", diskType) == 0
			&& detectDiskType (&diskType, imagefilename) < 0)
		return 1;

//
// *** Open the VDI, parse the MBR + EBRs and connect to the fuse service ***
//
	if (RT_FAILURE (VDInterfaceAdd (&vdError, "VD Error", VDINTERFACETYPE_ERROR,
																	&vdErrorCallbacks, NULL, &pVDifs)))
		usageAndExit ("invalid initialisation of VD interface");
	if (RT_FAILURE (VDCreate (&vdError, VDTYPE_HDD, &hdDisk)))
		usageAndExit ("invalid initialisation of VD interface");
	DISKopen (diskType, imagefilename);

	for (i = 0; i < differencingLen; i++)
	{
		char *diffType;
		char *diffFilename = differencing[i];
		detectDiskType (&diffType, diffFilename);
		DISKopen (diffType, diffFilename);
	}

	initialisePartitionTable ();

	myuid = geteuid ();
	mygid = getegid ();

	fuse_opt_add_arg (&fuseArgs, "vdfuse");

	{
		char fsname[strlen (imagefilename) + 12];
		strcpy (fsname, "-ofsname=\0");
		strcat (fsname, imagefilename);
		fuse_opt_add_arg (&fuseArgs, fsname);
	}

	fuse_opt_add_arg (&fuseArgs, "-osubtype=vdfuse");
	fuse_opt_add_arg (&fuseArgs, "-o");
	fuse_opt_add_arg (&fuseArgs, (allowall) ? "allow_other" : "allow_root");
	if (foreground)
		fuse_opt_add_arg (&fuseArgs, "-f");
	if (debug)
		fuse_opt_add_arg (&fuseArgs, "-d");
	fuse_opt_add_arg (&fuseArgs, mountpoint);

	return fuse_main (fuseArgs.argc, fuseArgs.argv, &fuseOperations
#if FUSE_USE_VERSION >= 26
										, NULL
#endif
		);
}
Exemple #3
0
static int tstVDBackendInfo(void)
{
    int rc;
#define MAX_BACKENDS 100
    VDBACKENDINFO aVDInfo[MAX_BACKENDS];
    unsigned cEntries;

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

    rc = VDBackendInfo(MAX_BACKENDS, aVDInfo, &cEntries);
    CHECK("VDBackendInfo()");

    for (unsigned i=0; i < cEntries; i++)
    {
        RTPrintf("Backend %u: name=%s capabilities=%#06x extensions=",
                 i, aVDInfo[i].pszBackend, aVDInfo[i].uBackendCaps);
        if (aVDInfo[i].paFileExtensions)
        {
            PCVDFILEEXTENSION pa = aVDInfo[i].paFileExtensions;
            while (pa->pszExtension != NULL)
            {
                if (pa != aVDInfo[i].paFileExtensions)
                    RTPrintf(",");
                RTPrintf("%s (%s)", pa->pszExtension, tstVDDeviceType(pa->enmType));
                pa++;
            }
            if (pa == aVDInfo[i].paFileExtensions)
                RTPrintf("<EMPTY>");
        }
        else
            RTPrintf("<NONE>");
        RTPrintf(" config=");
        if (aVDInfo[i].paConfigInfo)
        {
            PCVDCONFIGINFO pa = aVDInfo[i].paConfigInfo;
            while (pa->pszKey != NULL)
            {
                if (pa != aVDInfo[i].paConfigInfo)
                    RTPrintf(",");
                RTPrintf("(key=%s type=", pa->pszKey);
                switch (pa->enmValueType)
                {
                    case VDCFGVALUETYPE_INTEGER:
                        RTPrintf("integer");
                        break;
                    case VDCFGVALUETYPE_STRING:
                        RTPrintf("string");
                        break;
                    case VDCFGVALUETYPE_BYTES:
                        RTPrintf("bytes");
                        break;
                    default:
                        RTPrintf("INVALID!");
                }
                RTPrintf(" default=");
                if (pa->pszDefaultValue)
                    RTPrintf("%s", pa->pszDefaultValue);
                else
                    RTPrintf("<NONE>");
                RTPrintf(" flags=");
                if (!pa->uKeyFlags)
                    RTPrintf("none");
                unsigned cFlags = 0;
                if (pa->uKeyFlags & VD_CFGKEY_MANDATORY)
                {
                    if (cFlags)
                        RTPrintf(",");
                    RTPrintf("mandatory");
                    cFlags++;
                }
                if (pa->uKeyFlags & VD_CFGKEY_EXPERT)
                {
                    if (cFlags)
                        RTPrintf(",");
                    RTPrintf("expert");
                    cFlags++;
                }
                RTPrintf(")");
                pa++;
            }
            if (pa == aVDInfo[i].paConfigInfo)
                RTPrintf("<EMPTY>");
        }
        else
            RTPrintf("<NONE>");
        RTPrintf("\n");

        PVDINTERFACE pVDIfs = NULL;
        VDINTERFACECONFIG ic;

        ic.pfnAreKeysValid = tstAreKeysValid;
        ic.pfnQuerySize    = tstQuerySize;
        ic.pfnQuery        = tstQuery;

        rc = VDInterfaceAdd(&ic.Core, "tstVD-2_Config", VDINTERFACETYPE_CONFIG,
                            NULL, sizeof(VDINTERFACECONFIG), &pVDIfs);
        AssertRC(rc);

        char *pszLocation, *pszName;
        rc = aVDInfo[i].pfnComposeLocation(pVDIfs, &pszLocation);
        CHECK("pfnComposeLocation()");
        if (pszLocation)
        {
            RTMemFree(pszLocation);
            if (aVDInfo[i].uBackendCaps & VD_CAP_FILE)
            {
                RTPrintf("Non-NULL location returned for file-based backend!\n");
                return VERR_INTERNAL_ERROR;
            }
        }
        rc = aVDInfo[i].pfnComposeName(pVDIfs, &pszName);
        CHECK("pfnComposeName()");
        if (pszName)
        {
            RTMemFree(pszName);
            if (aVDInfo[i].uBackendCaps & VD_CAP_FILE)
            {
                RTPrintf("Non-NULL name returned for file-based backend!\n");
                return VERR_INTERNAL_ERROR;
            }
        }
    }

#undef CHECK
    return 0;
}
int main(int argc, char *argv[])
{
    int rc;

    RTR3InitExe(argc, &argv, 0);

    if (argc != 3)
    {
        RTPrintf("Usage: ./tstVDCopy <hdd1> <hdd2>\n");
        return 1;
    }

    RTPrintf("tstVDCopy: TESTING...\n");

    PVBOXHDD         pVD1 = NULL;
    PVBOXHDD         pVD2 = NULL;
    PVDINTERFACE     pVDIfs = NULL;
    VDINTERFACEERROR VDIfError;
    char *pszVD1 = NULL;
    char *pszVD2 = NULL;
    char *pbBuf1 = NULL;
    char *pbBuf2 = NULL;
    VDTYPE enmTypeVD1 = VDTYPE_INVALID;
    VDTYPE enmTypeVD2 = VDTYPE_INVALID;

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

    pbBuf1 = (char *)RTMemAllocZ(VD_MERGE_BUFFER_SIZE);
    pbBuf2 = (char *)RTMemAllocZ(VD_MERGE_BUFFER_SIZE);

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

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

    rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
                     argv[1], &pszVD1, &enmTypeVD1);
    CHECK("VDGetFormat() hdd1");

    rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
                     argv[2], &pszVD2, &enmTypeVD2);
    CHECK("VDGetFormat() hdd2");

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

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

    rc = VDOpen(pVD1, pszVD1, argv[1], VD_OPEN_FLAGS_NORMAL, NULL);
    CHECK("VDOpen() hdd1");

    rc = VDOpen(pVD2, pszVD2, argv[2], VD_OPEN_FLAGS_NORMAL, NULL);
    CHECK("VDOpen() hdd2");

    uint64_t cbSize1 = 0;
    uint64_t cbSize2 = 0;

    cbSize1 = VDGetSize(pVD1, 0);
    Assert(cbSize1 != 0);
    cbSize2 = VDGetSize(pVD1, 0);
    Assert(cbSize1 != 0);

    if (cbSize1 == cbSize2)
    {
        uint64_t uOffCurr = 0;

        /* Compare block by block. */
        while (uOffCurr < cbSize1)
        {
            size_t cbRead = RT_MIN((cbSize1 - uOffCurr), VD_MERGE_BUFFER_SIZE);

            rc = VDRead(pVD1, uOffCurr, pbBuf1, cbRead);
            CHECK("VDRead() hdd1");

            rc = VDRead(pVD2, uOffCurr, pbBuf2, cbRead);
            CHECK("VDRead() hdd2");

            if (memcmp(pbBuf1, pbBuf2, cbRead))
            {
                RTPrintf("tstVDCopy: Images differ uOffCurr=%llu\n", uOffCurr);
                /* Do byte by byte comparison. */
                for (size_t i = 0; i < cbRead; i++)
                {
                    if (pbBuf1[i] != pbBuf2[i])
                    {
                        RTPrintf("tstVDCopy: First different byte is at offset %llu\n", uOffCurr + i);
                        break;
                    }
                }
                break;
            }

            uOffCurr += cbRead;
        }
    }
    else
        RTPrintf("tstVDCopy: Images have different size hdd1=%llu hdd2=%llu\n", cbSize1, cbSize2);

    VDClose(pVD1, false);
    CHECK("VDClose() hdd1");

    VDClose(pVD2, false);
    CHECK("VDClose() hdd2");

    VDDestroy(pVD1);
    VDDestroy(pVD2);
    RTMemFree(pbBuf1);
    RTMemFree(pbBuf2);
#undef CHECK

    rc = VDShutdown();
    if (RT_FAILURE(rc))
    {
        RTPrintf("tstVDCopy: unloading backends failed! rc=%Rrc\n", rc);
        g_cErrors++;
    }
    /*
     * Summary
     */
    if (!g_cErrors)
        RTPrintf("tstVDCopy: SUCCESS\n");
    else
        RTPrintf("tstVDCopy: FAILURE - %d errors\n", g_cErrors);

    return !!g_cErrors;
}
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;
}