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; }
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 ); }
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; }