summaryrefslogtreecommitdiff
path: root/src/VBox/Storage/VHD.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Storage/VHD.cpp')
-rw-r--r--src/VBox/Storage/VHD.cpp960
1 files changed, 379 insertions, 581 deletions
diff --git a/src/VBox/Storage/VHD.cpp b/src/VBox/Storage/VHD.cpp
index fc3a17b5..c563a267 100644
--- a/src/VBox/Storage/VHD.cpp
+++ b/src/VBox/Storage/VHD.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -298,43 +298,74 @@ out:
*/
static int vhdLocatorUpdate(PVHDIMAGE pImage, PVHDPLE pLocator, const char *pszFilename)
{
- int rc;
- uint32_t cb, cbMaxLen = RT_BE2H_U32(pLocator->u32DataSpace) * VHD_SECTOR_SIZE;
+ int rc = VINF_SUCCESS;
+ uint32_t cb, cbMaxLen = RT_BE2H_U32(pLocator->u32DataSpace);
void *pvBuf = RTMemTmpAllocZ(cbMaxLen);
char *pszTmp;
if (!pvBuf)
- {
- rc = VERR_NO_MEMORY;
- goto out;
- }
+ return VERR_NO_MEMORY;
switch (RT_BE2H_U32(pLocator->u32Code))
{
case VHD_PLATFORM_CODE_WI2R:
- /* Update plain relative name. */
- cb = (uint32_t)strlen(pszFilename);
- if (cb > cbMaxLen)
+ {
+ if (RTPathStartsWithRoot(pszFilename))
{
- rc = VERR_FILENAME_TOO_LONG;
- goto out;
+ /* Convert to relative path. */
+ char szPath[RTPATH_MAX];
+ rc = RTPathCalcRelative(szPath, sizeof(szPath), pImage->pszFilename,
+ pszFilename);
+ if (RT_SUCCESS(rc))
+ {
+ /* Update plain relative name. */
+ cb = (uint32_t)strlen(szPath);
+ if (cb > cbMaxLen)
+ {
+ rc = VERR_FILENAME_TOO_LONG;
+ break;
+ }
+ memcpy(pvBuf, szPath, cb);
+ }
+ }
+ else
+ {
+ /* Update plain relative name. */
+ cb = (uint32_t)strlen(pszFilename);
+ if (cb > cbMaxLen)
+ {
+ rc = VERR_FILENAME_TOO_LONG;
+ break;
+ }
+ memcpy(pvBuf, pszFilename, cb);
}
- memcpy(pvBuf, pszFilename, cb);
pLocator->u32DataLength = RT_H2BE_U32(cb);
break;
+ }
case VHD_PLATFORM_CODE_WI2K:
/* Update plain absolute name. */
rc = RTPathAbs(pszFilename, (char *)pvBuf, cbMaxLen);
- if (RT_FAILURE(rc))
- goto out;
- pLocator->u32DataLength = RT_H2BE_U32((uint32_t)strlen((const char *)pvBuf));
+ if (RT_SUCCESS(rc))
+ pLocator->u32DataLength = RT_H2BE_U32((uint32_t)strlen((const char *)pvBuf));
break;
case VHD_PLATFORM_CODE_W2RU:
- /* Update unicode relative name. */
- rc = vhdFilenameToUtf16(pszFilename, (uint16_t *)pvBuf, cbMaxLen, &cb, false);
- if (RT_FAILURE(rc))
- goto out;
- pLocator->u32DataLength = RT_H2BE_U32(cb);
+ if (RTPathStartsWithRoot(pszFilename))
+ {
+ /* Convert to relative path. */
+ char szPath[RTPATH_MAX];
+ rc = RTPathCalcRelative(szPath, sizeof(szPath), pImage->pszFilename,
+ pszFilename);
+ if (RT_SUCCESS(rc))
+ rc = vhdFilenameToUtf16(szPath, (uint16_t *)pvBuf, cbMaxLen, &cb, false);
+ }
+ else
+ {
+ /* Update unicode relative name. */
+ rc = vhdFilenameToUtf16(pszFilename, (uint16_t *)pvBuf, cbMaxLen, &cb, false);
+ }
+
+ if (RT_SUCCESS(rc))
+ pLocator->u32DataLength = RT_H2BE_U32(cb);
break;
case VHD_PLATFORM_CODE_W2KU:
/* Update unicode absolute name. */
@@ -342,30 +373,29 @@ static int vhdLocatorUpdate(PVHDIMAGE pImage, PVHDPLE pLocator, const char *pszF
if (!pszTmp)
{
rc = VERR_NO_MEMORY;
- goto out;
+ break;
}
rc = RTPathAbs(pszFilename, pszTmp, cbMaxLen);
if (RT_FAILURE(rc))
{
RTMemTmpFree(pszTmp);
- goto out;
+ break;
}
rc = vhdFilenameToUtf16(pszTmp, (uint16_t *)pvBuf, cbMaxLen, &cb, false);
RTMemTmpFree(pszTmp);
- if (RT_FAILURE(rc))
- goto out;
- pLocator->u32DataLength = RT_H2BE_U32(cb);
+ if (RT_SUCCESS(rc))
+ pLocator->u32DataLength = RT_H2BE_U32(cb);
break;
default:
rc = VERR_NOT_IMPLEMENTED;
- goto out;
+ break;
}
- rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
- RT_BE2H_U64(pLocator->u64DataOffset),
- pvBuf, RT_BE2H_U32(pLocator->u32DataSpace) * VHD_SECTOR_SIZE,
- NULL);
-out:
+ if (RT_SUCCESS(rc))
+ rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
+ RT_BE2H_U64(pLocator->u64DataOffset),
+ pvBuf, cb);
+
if (pvBuf)
RTMemTmpFree(pvBuf);
return rc;
@@ -383,7 +413,7 @@ static int vhdDynamicHeaderUpdate(PVHDIMAGE pImage)
return VERR_VD_NOT_OPENED;
rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
- pImage->u64DataOffset, &ddh, sizeof(ddh), NULL);
+ pImage->u64DataOffset, &ddh, sizeof(ddh));
if (RT_FAILURE(rc))
return rc;
if (memcmp(ddh.Cookie, VHD_DYNAMIC_DISK_HEADER_COOKIE, VHD_DYNAMIC_DISK_HEADER_COOKIE_SIZE) != 0)
@@ -433,7 +463,7 @@ static int vhdDynamicHeaderUpdate(PVHDIMAGE pImage)
ddh.Checksum = 0;
ddh.Checksum = RT_H2BE_U32(vhdChecksum(&ddh, sizeof(ddh)));
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
- pImage->u64DataOffset, &ddh, sizeof(ddh), NULL);
+ pImage->u64DataOffset, &ddh, sizeof(ddh));
return rc;
}
@@ -455,12 +485,12 @@ static int vhdUpdateFooter(PVHDIMAGE pImage)
if (pImage->pBlockAllocationTable)
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0,
- &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL);
+ &pImage->vhdFooterCopy, sizeof(VHDFooter));
if (RT_SUCCESS(rc))
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
pImage->uCurrentEndOfFile, &pImage->vhdFooterCopy,
- sizeof(VHDFooter), NULL);
+ sizeof(VHDFooter));
return rc;
}
@@ -496,7 +526,7 @@ static int vhdFlushImage(PVHDIMAGE pImage)
* Write the block allocation table after the copy of the disk footer and the dynamic disk header.
*/
vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->uBlockAllocationTableOffset,
- pBlockAllocationTableToWrite, cbBlockAllocationTableToWrite, NULL);
+ pBlockAllocationTableToWrite, cbBlockAllocationTableToWrite);
if (pImage->fDynHdrNeedsUpdate)
rc = vhdDynamicHeaderUpdate(pImage);
RTMemFree(pBlockAllocationTableToWrite);
@@ -529,7 +559,7 @@ static int vhdFreeImage(PVHDIMAGE pImage, bool fDelete)
if (!fDelete)
vhdFlushImage(pImage);
- vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
+ rc = vdIfIoIntFileClose(pImage->pIfIo, pImage->pStorage);
pImage->pStorage = NULL;
}
@@ -550,7 +580,7 @@ static int vhdFreeImage(PVHDIMAGE pImage, bool fDelete)
}
if (fDelete && pImage->pszFilename)
- rc = vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
+ vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
}
LogFlowFunc(("returns %Rrc\n", rc));
@@ -615,11 +645,11 @@ static int vhdAsyncExpansionComplete(PVHDIMAGE pImage, PVDIOCTX pIoCtx, PVHDIMAG
* do anything if this fails. */
if (uStatus == VHDIMAGEEXPAND_STEP_SUCCESS)
{
- rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage,
- pImage->uBlockAllocationTableOffset
- + pExpand->idxBatAllocated * sizeof(uint32_t),
- &pImage->pBlockAllocationTable[pExpand->idxBatAllocated],
- sizeof(uint32_t), pIoCtx, NULL, NULL);
+ rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
+ pImage->uBlockAllocationTableOffset
+ + pExpand->idxBatAllocated * sizeof(uint32_t),
+ &pImage->pBlockAllocationTable[pExpand->idxBatAllocated],
+ sizeof(uint32_t), pIoCtx, NULL, NULL);
fIoInProgress |= rc == VERR_VD_ASYNC_IO_IN_PROGRESS;
}
}
@@ -632,10 +662,10 @@ static int vhdAsyncExpansionComplete(PVHDIMAGE pImage, PVDIOCTX pIoCtx, PVHDIMAG
AssertRC(rc);
pImage->uCurrentEndOfFile = pExpand->cbEofOld;
- rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage,
- pImage->uCurrentEndOfFile,
- &pImage->vhdFooterCopy, sizeof(VHDFooter),
- pIoCtx, NULL, NULL);
+ rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
+ pImage->uCurrentEndOfFile,
+ &pImage->vhdFooterCopy, sizeof(VHDFooter),
+ pIoCtx, NULL, NULL);
fIoInProgress |= rc == VERR_VD_ASYNC_IO_IN_PROGRESS;
}
@@ -695,8 +725,7 @@ static int vhdLoadDynamicDisk(PVHDIMAGE pImage, uint64_t uDynamicDiskHeaderOffse
* Read the dynamic disk header.
*/
rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, uDynamicDiskHeaderOffset,
- &vhdDynamicDiskHeader, sizeof(VHDDynamicDiskHeader),
- NULL);
+ &vhdDynamicDiskHeader, sizeof(VHDDynamicDiskHeader));
if (memcmp(vhdDynamicDiskHeader.Cookie, VHD_DYNAMIC_DISK_HEADER_COOKIE, VHD_DYNAMIC_DISK_HEADER_COOKIE_SIZE))
return VERR_INVALID_PARAMETER;
@@ -737,8 +766,7 @@ static int vhdLoadDynamicDisk(PVHDIMAGE pImage, uint64_t uDynamicDiskHeaderOffse
pImage->uBlockAllocationTableOffset = uBlockAllocationTableOffset;
rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
uBlockAllocationTableOffset, pBlockAllocationTable,
- pImage->cBlockAllocationTableEntries * sizeof(uint32_t),
- NULL);
+ pImage->cBlockAllocationTableEntries * sizeof(uint32_t));
/*
* Because the offset entries inside the allocation table are stored big endian
@@ -791,9 +819,29 @@ static int vhdOpenImage(PVHDIMAGE pImage, unsigned uOpenFlags)
pImage->uCurrentEndOfFile = FileSize - sizeof(VHDFooter);
rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, pImage->uCurrentEndOfFile,
- &vhdFooter, sizeof(VHDFooter), NULL);
- if (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0)
- return VERR_VD_VHD_INVALID_HEADER;
+ &vhdFooter, sizeof(VHDFooter));
+ if (RT_SUCCESS(rc))
+ {
+ if (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0)
+ {
+ /*
+ * There is also a backup header at the beginning in case the image got corrupted.
+ * Such corrupted images are detected here to let the open handler repair it later.
+ */
+ rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, 0,
+ &vhdFooter, sizeof(VHDFooter));
+ if (RT_SUCCESS(rc))
+ {
+ if (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0)
+ rc = VERR_VD_VHD_INVALID_HEADER;
+ else
+ rc = VERR_VD_IMAGE_CORRUPTED;
+ }
+ }
+ }
+
+ if (RT_FAILURE(rc))
+ return rc;
switch (RT_BE2H_U32(vhdFooter.DiskType))
{
@@ -938,29 +986,26 @@ static void vhdSetDiskGeometry(PVHDIMAGE pImage, uint64_t cbSize)
static uint32_t vhdAllocateParentLocators(PVHDIMAGE pImage, VHDDynamicDiskHeader *pDDH, uint64_t u64Offset)
{
PVHDPLE pLocator = pDDH->ParentLocatorEntry;
- /* Relative Windows path. */
- pLocator->u32Code = RT_H2BE_U32(VHD_PLATFORM_CODE_WI2R);
- pLocator->u32DataSpace = RT_H2BE_U32(VHD_RELATIVE_MAX_PATH / VHD_SECTOR_SIZE);
- pLocator->u64DataOffset = RT_H2BE_U64(u64Offset);
- u64Offset += VHD_RELATIVE_MAX_PATH;
- pLocator++;
- /* Absolute Windows path. */
- pLocator->u32Code = RT_H2BE_U32(VHD_PLATFORM_CODE_WI2K);
- pLocator->u32DataSpace = RT_H2BE_U32(VHD_ABSOLUTE_MAX_PATH / VHD_SECTOR_SIZE);
+
+ /*
+ * The VHD spec states that the DataSpace field holds the number of sectors
+ * required to store the parent locator path.
+ * As it turned out VPC and Hyper-V store the amount of bytes reserved for the
+ * path and not the number of sectors.
+ */
+
+ /* Unicode absolute Windows path. */
+ pLocator->u32Code = RT_H2BE_U32(VHD_PLATFORM_CODE_W2KU);
+ pLocator->u32DataSpace = RT_H2BE_U32(VHD_ABSOLUTE_MAX_PATH * sizeof(RTUTF16));
pLocator->u64DataOffset = RT_H2BE_U64(u64Offset);
- u64Offset += VHD_ABSOLUTE_MAX_PATH;
pLocator++;
+ u64Offset += VHD_ABSOLUTE_MAX_PATH * sizeof(RTUTF16);
/* Unicode relative Windows path. */
pLocator->u32Code = RT_H2BE_U32(VHD_PLATFORM_CODE_W2RU);
- pLocator->u32DataSpace = RT_H2BE_U32(VHD_RELATIVE_MAX_PATH * sizeof(RTUTF16) / VHD_SECTOR_SIZE);
+ pLocator->u32DataSpace = RT_H2BE_U32(VHD_RELATIVE_MAX_PATH * sizeof(RTUTF16));
pLocator->u64DataOffset = RT_H2BE_U64(u64Offset);
u64Offset += VHD_RELATIVE_MAX_PATH * sizeof(RTUTF16);
- pLocator++;
- /* Unicode absolute Windows path. */
- pLocator->u32Code = RT_H2BE_U32(VHD_PLATFORM_CODE_W2KU);
- pLocator->u32DataSpace = RT_H2BE_U32(VHD_ABSOLUTE_MAX_PATH * sizeof(RTUTF16) / VHD_SECTOR_SIZE);
- pLocator->u64DataOffset = RT_H2BE_U64(u64Offset);
- return u64Offset + VHD_ABSOLUTE_MAX_PATH * sizeof(RTUTF16);
+ return u64Offset;
}
/**
@@ -1013,7 +1058,7 @@ static int vhdCreateDynamicImage(PVHDIMAGE pImage, uint64_t cbSize)
return vdIfError(pImage->pIfError, VERR_NO_MEMORY, RT_SRC_POS, N_("VHD: cannot set the file size for '%s'"), pImage->pszFilename);
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0, pvTmp,
- pImage->uCurrentEndOfFile + sizeof(VHDFooter), NULL);
+ pImage->uCurrentEndOfFile + sizeof(VHDFooter));
if (RT_FAILURE(rc))
{
RTMemTmpFree(pvTmp);
@@ -1034,15 +1079,14 @@ static int vhdCreateDynamicImage(PVHDIMAGE pImage, uint64_t cbSize)
DynamicDiskHeader.Checksum = RT_H2BE_U32(vhdChecksum(&DynamicDiskHeader, sizeof(DynamicDiskHeader)));
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, sizeof(VHDFooter),
- &DynamicDiskHeader, sizeof(DynamicDiskHeader), NULL);
+ &DynamicDiskHeader, sizeof(DynamicDiskHeader));
if (RT_FAILURE(rc))
return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VHD: cannot write dynamic disk header to image '%s'"), pImage->pszFilename);
/* Write BAT. */
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->uBlockAllocationTableOffset,
pImage->pBlockAllocationTable,
- pImage->cBlockAllocationTableEntries * sizeof(uint32_t),
- NULL);
+ pImage->cBlockAllocationTableEntries * sizeof(uint32_t));
if (RT_FAILURE(rc))
return vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VHD: cannot write BAT to image '%s'"), pImage->pszFilename);
@@ -1162,7 +1206,7 @@ static int vhdCreateImage(PVHDIMAGE pImage, uint64_t cbSize,
/* Store the footer */
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->uCurrentEndOfFile,
- &Footer, sizeof(Footer), NULL);
+ &Footer, sizeof(Footer));
if (RT_FAILURE(rc))
{
vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VHD: cannot write footer to image '%s'"), pImage->pszFilename);
@@ -1173,7 +1217,7 @@ static int vhdCreateImage(PVHDIMAGE pImage, uint64_t cbSize,
if (!(uImageFlags & VD_IMAGE_FLAGS_FIXED))
{
/* Write the copy of the footer. */
- rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0, &Footer, sizeof(Footer), NULL);
+ rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, 0, &Footer, sizeof(Footer));
if (RT_FAILURE(rc))
{
vdIfError(pImage->pIfError, rc, RT_SRC_POS, N_("VHD: cannot write a copy of footer to image '%s'"), pImage->pszFilename);
@@ -1220,14 +1264,26 @@ static int vhdCheckIfValid(const char *pszFilename, PVDINTERFACE pVDIfsDisk,
}
rc = vdIfIoIntFileReadSync(pIfIo, pStorage, cbFile - sizeof(VHDFooter),
- &vhdFooter, sizeof(VHDFooter), NULL);
- if (RT_FAILURE(rc) || (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0))
- rc = VERR_VD_VHD_INVALID_HEADER;
- else
+ &vhdFooter, sizeof(VHDFooter));
+ if (RT_SUCCESS(rc))
{
- *penmType = VDTYPE_HDD;
- rc = VINF_SUCCESS;
+ if (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0)
+ {
+ /*
+ * There is also a backup header at the beginning in case the image got corrupted.
+ * Such corrupted images are detected here to let the open handler repair it later.
+ */
+ rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0, &vhdFooter, sizeof(VHDFooter));
+ if ( RT_FAILURE(rc)
+ || (memcmp(vhdFooter.Cookie, VHD_FOOTER_COOKIE, VHD_FOOTER_COOKIE_SIZE) != 0))
+ rc = VERR_VD_VHD_INVALID_HEADER;
+ }
+
+ if (RT_SUCCESS(rc))
+ *penmType = VDTYPE_HDD;
}
+ else
+ rc = VERR_VD_VHD_INVALID_HEADER;
vdIfIoIntFileClose(pIfIo, pStorage);
@@ -1422,18 +1478,16 @@ static int vhdClose(void *pBackendData, bool fDelete)
}
/** @copydoc VBOXHDDBACKEND::pfnRead */
-static int vhdRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
- size_t cbBuf, size_t *pcbActuallyRead)
+static int vhdRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
+ PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
{
- LogFlowFunc(("pBackendData=%p uOffset=%#llu pvBuf=%p cbBuf=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbActuallyRead));
PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
int rc = VINF_SUCCESS;
- if (uOffset + cbBuf > pImage->cbSize)
- {
- rc = VERR_INVALID_PARAMETER;
- goto out;
- }
+ LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbRead=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
+
+ if (uOffset + cbRead > pImage->cbSize)
+ return VERR_INVALID_PARAMETER;
/*
* If we have a dynamic disk image, we need to find the data block and sector to read.
@@ -1453,7 +1507,7 @@ static int vhdRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
/*
* Clip read range to remain in this data block.
*/
- cbBuf = RT_MIN(cbBuf, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
+ cbRead = RT_MIN(cbRead, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
/*
* If the block is not allocated the content of the entry is ~0
@@ -1463,17 +1517,20 @@ static int vhdRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
else
{
uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
- LogFlowFunc(("uVhdOffset=%llu cbBuf=%u\n", uVhdOffset, cbBuf));
+ LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
/* Read in the block's bitmap. */
- rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
+ PVDMETAXFER pMetaXfer;
+ rc = vdIfIoIntFileReadMeta(pImage->pIfIo, pImage->pStorage,
((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
pImage->pu8Bitmap, pImage->cbDataBlockBitmap,
- NULL);
+ pIoCtx, &pMetaXfer, NULL, NULL);
+
if (RT_SUCCESS(rc))
{
uint32_t cSectors = 0;
+ vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer);
if (vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
{
cBATEntryIndex++;
@@ -1484,18 +1541,18 @@ static int vhdRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
* can from child. Note that only sectors that are marked dirty
* must be read from child.
*/
- while ( (cSectors < (cbBuf / VHD_SECTOR_SIZE))
+ while ( (cSectors < (cbRead / VHD_SECTOR_SIZE))
&& vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
{
cBATEntryIndex++;
cSectors++;
}
- cbBuf = cSectors * VHD_SECTOR_SIZE;
+ cbRead = cSectors * VHD_SECTOR_SIZE;
- LogFlowFunc(("uVhdOffset=%llu cbBuf=%u\n", uVhdOffset, cbBuf));
- rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
- uVhdOffset, pvBuf, cbBuf, NULL);
+ LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
+ rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage,
+ uVhdOffset, pIoCtx, cbRead);
}
else
{
@@ -1510,56 +1567,46 @@ static int vhdRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
cBATEntryIndex++;
cSectors = 1;
- while ( (cSectors < (cbBuf / VHD_SECTOR_SIZE))
+ while ( (cSectors < (cbRead / VHD_SECTOR_SIZE))
&& !vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
{
cBATEntryIndex++;
cSectors++;
}
- cbBuf = cSectors * VHD_SECTOR_SIZE;
- LogFunc(("Sectors free: uVhdOffset=%llu cbBuf=%u\n", uVhdOffset, cbBuf));
+ cbRead = cSectors * VHD_SECTOR_SIZE;
+ LogFunc(("Sectors free: uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
rc = VERR_VD_BLOCK_FREE;
}
}
else
- AssertMsgFailed(("Reading block bitmap failed rc=%Rrc\n", rc));
+ AssertMsg(rc == VERR_VD_NOT_ENOUGH_METADATA, ("Reading block bitmap failed rc=%Rrc\n", rc));
}
}
else
- rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf, cbBuf, NULL);
+ rc = vdIfIoIntFileReadUser(pImage->pIfIo, pImage->pStorage, uOffset, pIoCtx, cbRead);
- if ( RT_SUCCESS(rc)
- || rc == VERR_VD_BLOCK_FREE)
- {
- if (pcbActuallyRead)
- *pcbActuallyRead = cbBuf;
-
- Log2(("vhdRead: off=%#llx pvBuf=%p cbBuf=%d\n"
- "%.*Rhxd\n",
- uOffset, pvBuf, cbBuf, cbBuf, pvBuf));
- }
+ if (pcbActuallyRead)
+ *pcbActuallyRead = cbRead;
-out:
- LogFlowFunc(("returns %Rrc\n", rc));
+ LogFlowFunc(("returns rc=%Rrc\n", rc));
return rc;
}
/** @copydoc VBOXHDDBACKEND::pfnWrite */
-static int vhdWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
- size_t cbBuf, size_t *pcbWriteProcess,
- size_t *pcbPreRead, size_t *pcbPostRead, unsigned fWrite)
+static int vhdWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
+ PVDIOCTX pIoCtx, size_t *pcbWriteProcess, size_t *pcbPreRead,
+ size_t *pcbPostRead, unsigned fWrite)
{
- LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbBuf=%zu pcbWriteProcess=%#p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbWriteProcess));
PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
int rc = VINF_SUCCESS;
- LogFlowFunc(("pBackendData=%p uOffset=%llu pvBuf=%p cbBuf=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
- pBackendData, uOffset, pvBuf, cbBuf, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite));
+ LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
+ pBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite));
AssertPtr(pImage);
Assert(uOffset % VHD_SECTOR_SIZE == 0);
- Assert(cbBuf % VHD_SECTOR_SIZE == 0);
+ Assert(cbWrite % VHD_SECTOR_SIZE == 0);
if (pImage->pBlockAllocationTable)
{
@@ -1574,7 +1621,7 @@ static int vhdWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
/*
* Clip write range.
*/
- cbBuf = RT_MIN(cbBuf, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
+ cbWrite = RT_MIN(cbWrite, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
/*
* If the block is not allocated the content of the entry is ~0
@@ -1591,105 +1638,202 @@ static int vhdWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
if (fWrite & VD_WRITE_NO_ALLOC)
{
*pcbPreRead = cBATEntryIndex * VHD_SECTOR_SIZE;
- *pcbPostRead = pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE - cbBuf - *pcbPreRead;
+ *pcbPostRead = pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE - cbWrite - *pcbPreRead;
if (pcbWriteProcess)
- *pcbWriteProcess = cbBuf;
- rc = VERR_VD_BLOCK_FREE;
- goto out;
+ *pcbWriteProcess = cbWrite;
+ return VERR_VD_BLOCK_FREE;
}
- size_t cbNewBlock = pImage->cbDataBlock + (pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE);
- uint8_t *pNewBlock = (uint8_t *)RTMemAllocZ(cbNewBlock);
+ PVHDIMAGEEXPAND pExpand = (PVHDIMAGEEXPAND)RTMemAllocZ(RT_OFFSETOF(VHDIMAGEEXPAND, au8Bitmap[pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE]));
+ bool fIoInProgress = false;
- if (!pNewBlock)
+ if (!pExpand)
+ return VERR_NO_MEMORY;
+
+ pExpand->cbEofOld = pImage->uCurrentEndOfFile;
+ pExpand->idxBatAllocated = cBlockAllocationTableEntry;
+ pExpand->idxBlockBe = RT_H2BE_U32(pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE);
+
+ /* Set the bits for all sectors having been written. */
+ for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++)
{
- rc = VERR_NO_MEMORY;
- goto out;
+ /* No need to check for a changed value because this is an initial write. */
+ vhdBlockBitmapSectorSet(pImage, pExpand->au8Bitmap, cBATEntryIndex);
+ cBATEntryIndex++;
}
- /*
- * Write the new block at the current end of the file.
- */
- rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, pImage->uCurrentEndOfFile,
- pNewBlock, cbNewBlock, NULL);
- AssertRC(rc);
+ do
+ {
+ /*
+ * Start with the sector bitmap.
+ */
+ rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
+ pImage->uCurrentEndOfFile,
+ pExpand->au8Bitmap,
+ pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE, pIoCtx,
+ vhdAsyncExpansionDataBlockBitmapComplete,
+ pExpand);
+ if (RT_SUCCESS(rc))
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
+ else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+ fIoInProgress = true;
+ else
+ {
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ break;
+ }
- /*
- * Set the new end of the file and link the new block into the BAT.
- */
- pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
- pImage->uCurrentEndOfFile += cbNewBlock;
- RTMemFree(pNewBlock);
- /* Write the updated BAT and the footer to remain in a consistent state. */
- rc = vhdFlushImage(pImage);
- AssertRC(rc);
- }
+ /*
+ * Write the new block at the current end of the file.
+ */
+ rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
+ pImage->uCurrentEndOfFile + pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE,
+ pIoCtx, cbWrite,
+ vhdAsyncExpansionDataComplete,
+ pExpand);
+ if (RT_SUCCESS(rc))
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
+ else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+ fIoInProgress = true;
+ else
+ {
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ break;
+ }
- /*
- * Calculate the real offset in the file.
- */
- uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
+ /*
+ * Write entry in the BAT.
+ */
+ rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
+ pImage->uBlockAllocationTableOffset + cBlockAllocationTableEntry * sizeof(uint32_t),
+ &pExpand->idxBlockBe, sizeof(uint32_t), pIoCtx,
+ vhdAsyncExpansionBatUpdateComplete,
+ pExpand);
+ if (RT_SUCCESS(rc))
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
+ else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+ fIoInProgress = true;
+ else
+ {
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ break;
+ }
- /* Write data. */
- vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uVhdOffset,
- pvBuf, cbBuf, NULL);
+ /*
+ * Set the new end of the file and link the new block into the BAT.
+ */
+ pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
+ pImage->uCurrentEndOfFile += pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE + pImage->cbDataBlock;
- /* Read in the block's bitmap. */
- rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
- ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
- pImage->pu8Bitmap, pImage->cbDataBlockBitmap,
- NULL);
- if (RT_SUCCESS(rc))
+ /* Update the footer. */
+ rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
+ pImage->uCurrentEndOfFile,
+ &pImage->vhdFooterCopy,
+ sizeof(VHDFooter), pIoCtx,
+ vhdAsyncExpansionFooterUpdateComplete,
+ pExpand);
+ if (RT_SUCCESS(rc))
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
+ else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+ fIoInProgress = true;
+ else
+ {
+ VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
+ break;
+ }
+
+ } while (0);
+
+ if (!fIoInProgress)
+ vhdAsyncExpansionComplete(pImage, pIoCtx, pExpand);
+ else
+ rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
+ }
+ else
{
- bool fChanged = false;
+ /*
+ * Calculate the real offset in the file.
+ */
+ uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
- /* Set the bits for all sectors having been written. */
- for (uint32_t iSector = 0; iSector < (cbBuf / VHD_SECTOR_SIZE); iSector++)
+ /* Read in the block's bitmap. */
+ PVDMETAXFER pMetaXfer;
+ rc = vdIfIoIntFileReadMeta(pImage->pIfIo, pImage->pStorage,
+ ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
+ pImage->pu8Bitmap,
+ pImage->cbDataBlockBitmap, pIoCtx,
+ &pMetaXfer, NULL, NULL);
+ if (RT_SUCCESS(rc))
{
- fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex);
- cBATEntryIndex++;
- }
+ vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer);
- if (fChanged)
- {
- /* Write the bitmap back. */
- rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
- ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
- pImage->pu8Bitmap, pImage->cbDataBlockBitmap,
- NULL);
+ /* Write data. */
+ rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
+ uVhdOffset, pIoCtx, cbWrite,
+ NULL, NULL);
+ if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
+ {
+ bool fChanged = false;
+
+ /* Set the bits for all sectors having been written. */
+ for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++)
+ {
+ fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex);
+ cBATEntryIndex++;
+ }
+
+ /* Only write the bitmap if it was changed. */
+ if (fChanged)
+ {
+ /*
+ * Write the bitmap back.
+ *
+ * @note We don't have a completion callback here because we
+ * can't do anything if the write fails for some reason.
+ * The error will propagated to the device/guest
+ * by the generic VD layer already and we don't need
+ * to rollback anything here.
+ */
+ rc = vdIfIoIntFileWriteMeta(pImage->pIfIo, pImage->pStorage,
+ ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
+ pImage->pu8Bitmap,
+ pImage->cbDataBlockBitmap,
+ pIoCtx, NULL, NULL);
+ }
+ }
}
}
}
else
- {
- rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, uOffset, pvBuf, cbBuf, NULL);
- }
+ rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
+ uOffset, pIoCtx, cbWrite, NULL, NULL);
if (pcbWriteProcess)
- *pcbWriteProcess = cbBuf;
+ *pcbWriteProcess = cbWrite;
/* Stay on the safe side. Do not run the risk of confusing the higher
* level, as that can be pretty lethal to image consistency. */
*pcbPreRead = 0;
*pcbPostRead = 0;
-out:
- LogFlowFunc(("returns %Rrc\n", rc));
return rc;
}
/** @copydoc VBOXHDDBACKEND::pfnFlush */
-static int vhdFlush(void *pBackendData)
+static int vhdFlush(void *pBackendData, PVDIOCTX pIoCtx)
{
- LogFlowFunc(("pBackendData=%#p", pBackendData));
PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
- int rc;
- rc = vhdFlushImage(pImage);
- LogFlowFunc(("returns %Rrc\n", rc));
- return rc;
+ /* No need to write anything here. Data is always updated on a write. */
+ return vdIfIoIntFileFlush(pImage->pIfIo, pImage->pStorage, pIoCtx, NULL, NULL);
}
/** @copydoc VBOXHDDBACKEND::pfnGetVersion */
@@ -1708,6 +1852,22 @@ static unsigned vhdGetVersion(void *pBackendData)
return ver;
}
+/** @copydoc VBOXHDDBACKEND::pfnGetSectorSize */
+static uint32_t vhdGetSectorSize(void *pBackendData)
+{
+ LogFlowFunc(("pBackendData=%#p\n", pBackendData));
+ PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
+ uint32_t cb = 0;
+
+ AssertPtr(pImage);
+
+ if (pImage)
+ cb = 512;
+
+ LogFlowFunc(("returns %zu\n", cb));
+ return cb;
+}
+
/** @copydoc VBOXHDDBACKEND::pfnGetSize */
static uint64_t vhdGetSize(void *pBackendData)
{
@@ -1891,7 +2051,9 @@ static int vhdSetOpenFlags(void *pBackendData, unsigned uOpenFlags)
int rc;
/* Image must be opened and the new flags must be valid. */
- if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
+ if (!pImage || (uOpenFlags & ~( VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO
+ | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE
+ | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS)))
{
rc = VERR_INVALID_PARAMETER;
goto out;
@@ -2255,368 +2417,6 @@ static int vhdSetParentFilename(void *pBackendData, const char *pszParentFilenam
return rc;
}
-/** @copydoc VBOXHDDBACKEND::pfnAsyncRead */
-static int vhdAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
- PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
-{
- PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
- int rc = VINF_SUCCESS;
-
- LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbRead=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
-
- if (uOffset + cbRead > pImage->cbSize)
- return VERR_INVALID_PARAMETER;
-
- /*
- * If we have a dynamic disk image, we need to find the data block and sector to read.
- */
- if (pImage->pBlockAllocationTable)
- {
- /*
- * Get the data block first.
- */
- uint32_t cBlockAllocationTableEntry = (uOffset / VHD_SECTOR_SIZE) / pImage->cSectorsPerDataBlock;
- uint32_t cBATEntryIndex = (uOffset / VHD_SECTOR_SIZE) % pImage->cSectorsPerDataBlock;
- uint64_t uVhdOffset;
-
- LogFlowFunc(("cBlockAllocationTableEntry=%u cBatEntryIndex=%u\n", cBlockAllocationTableEntry, cBATEntryIndex));
- LogFlowFunc(("BlockAllocationEntry=%u\n", pImage->pBlockAllocationTable[cBlockAllocationTableEntry]));
-
- /*
- * Clip read range to remain in this data block.
- */
- cbRead = RT_MIN(cbRead, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
-
- /*
- * If the block is not allocated the content of the entry is ~0
- */
- if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U)
- rc = VERR_VD_BLOCK_FREE;
- else
- {
- uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
- LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
-
- /* Read in the block's bitmap. */
- PVDMETAXFER pMetaXfer;
- rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pImage->pStorage,
- ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
- pImage->pu8Bitmap, pImage->cbDataBlockBitmap,
- pIoCtx, &pMetaXfer, NULL, NULL);
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cSectors = 0;
-
- vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer);
- if (vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
- {
- cBATEntryIndex++;
- cSectors = 1;
-
- /*
- * The first sector being read is marked dirty, read as much as we
- * can from child. Note that only sectors that are marked dirty
- * must be read from child.
- */
- while ( (cSectors < (cbRead / VHD_SECTOR_SIZE))
- && vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
- {
- cBATEntryIndex++;
- cSectors++;
- }
-
- cbRead = cSectors * VHD_SECTOR_SIZE;
-
- LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
- rc = vdIfIoIntFileReadUserAsync(pImage->pIfIo, pImage->pStorage,
- uVhdOffset, pIoCtx, cbRead);
- }
- else
- {
- /*
- * The first sector being read is marked clean, so we should read from
- * our parent instead, but only as much as there are the following
- * clean sectors, because the block may still contain dirty sectors
- * further on. We just need to compute the number of clean sectors
- * and pass it to our caller along with the notification that they
- * should be read from the parent.
- */
- cBATEntryIndex++;
- cSectors = 1;
-
- while ( (cSectors < (cbRead / VHD_SECTOR_SIZE))
- && !vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
- {
- cBATEntryIndex++;
- cSectors++;
- }
-
- cbRead = cSectors * VHD_SECTOR_SIZE;
- LogFunc(("Sectors free: uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
- rc = VERR_VD_BLOCK_FREE;
- }
- }
- else
- AssertMsg(rc == VERR_VD_NOT_ENOUGH_METADATA, ("Reading block bitmap failed rc=%Rrc\n", rc));
- }
- }
- else
- rc = vdIfIoIntFileReadUserAsync(pImage->pIfIo, pImage->pStorage, uOffset, pIoCtx, cbRead);
-
- if (pcbActuallyRead)
- *pcbActuallyRead = cbRead;
-
- LogFlowFunc(("returns rc=%Rrc\n", rc));
- return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncWrite */
-static int vhdAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
- PVDIOCTX pIoCtx,
- size_t *pcbWriteProcess, size_t *pcbPreRead,
- size_t *pcbPostRead, unsigned fWrite)
-{
- PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
- int rc = VINF_SUCCESS;
-
- LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
- pBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite));
-
- AssertPtr(pImage);
- Assert(uOffset % VHD_SECTOR_SIZE == 0);
- Assert(cbWrite % VHD_SECTOR_SIZE == 0);
-
- if (pImage->pBlockAllocationTable)
- {
- /*
- * Get the data block first.
- */
- uint32_t cSector = uOffset / VHD_SECTOR_SIZE;
- uint32_t cBlockAllocationTableEntry = cSector / pImage->cSectorsPerDataBlock;
- uint32_t cBATEntryIndex = cSector % pImage->cSectorsPerDataBlock;
- uint64_t uVhdOffset;
-
- /*
- * Clip write range.
- */
- cbWrite = RT_MIN(cbWrite, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
-
- /*
- * If the block is not allocated the content of the entry is ~0
- * and we need to allocate a new block. Note that while blocks are
- * allocated with a relatively big granularity, each sector has its
- * own bitmap entry, indicating whether it has been written or not.
- * So that means for the purposes of the higher level that the
- * granularity is invisible. This means there's no need to return
- * VERR_VD_BLOCK_FREE unless the block hasn't been allocated yet.
- */
- if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U)
- {
- /* Check if the block allocation should be suppressed. */
- if (fWrite & VD_WRITE_NO_ALLOC)
- {
- *pcbPreRead = cBATEntryIndex * VHD_SECTOR_SIZE;
- *pcbPostRead = pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE - cbWrite - *pcbPreRead;
-
- if (pcbWriteProcess)
- *pcbWriteProcess = cbWrite;
- return VERR_VD_BLOCK_FREE;
- }
-
- PVHDIMAGEEXPAND pExpand = (PVHDIMAGEEXPAND)RTMemAllocZ(RT_OFFSETOF(VHDIMAGEEXPAND, au8Bitmap[pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE]));
- bool fIoInProgress = false;
-
- if (!pExpand)
- return VERR_NO_MEMORY;
-
- pExpand->cbEofOld = pImage->uCurrentEndOfFile;
- pExpand->idxBatAllocated = cBlockAllocationTableEntry;
- pExpand->idxBlockBe = RT_H2BE_U32(pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE);
-
- /* Set the bits for all sectors having been written. */
- for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++)
- {
- /* No need to check for a changed value because this is an initial write. */
- vhdBlockBitmapSectorSet(pImage, pExpand->au8Bitmap, cBATEntryIndex);
- cBATEntryIndex++;
- }
-
- do
- {
- /*
- * Start with the sector bitmap.
- */
- rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage,
- pImage->uCurrentEndOfFile,
- pExpand->au8Bitmap,
- pImage->cbDataBlockBitmap, pIoCtx,
- vhdAsyncExpansionDataBlockBitmapComplete,
- pExpand);
- if (RT_SUCCESS(rc))
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
- else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
- fIoInProgress = true;
- else
- {
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- break;
- }
-
-
- /*
- * Write the new block at the current end of the file.
- */
- rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pImage->pStorage,
- pImage->uCurrentEndOfFile + pImage->cbDataBlockBitmap,
- pIoCtx, cbWrite,
- vhdAsyncExpansionDataComplete,
- pExpand);
- if (RT_SUCCESS(rc))
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
- else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
- fIoInProgress = true;
- else
- {
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- break;
- }
-
- /*
- * Write entry in the BAT.
- */
- rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage,
- pImage->uBlockAllocationTableOffset + cBlockAllocationTableEntry * sizeof(uint32_t),
- &pExpand->idxBlockBe,
- sizeof(uint32_t), pIoCtx,
- vhdAsyncExpansionBatUpdateComplete,
- pExpand);
- if (RT_SUCCESS(rc))
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
- else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
- fIoInProgress = true;
- else
- {
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- break;
- }
-
- /*
- * Set the new end of the file and link the new block into the BAT.
- */
- pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
- pImage->uCurrentEndOfFile += pImage->cbDataBlockBitmap + pImage->cbDataBlock;
-
- /* Update the footer. */
- rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage,
- pImage->uCurrentEndOfFile,
- &pImage->vhdFooterCopy,
- sizeof(VHDFooter), pIoCtx,
- vhdAsyncExpansionFooterUpdateComplete,
- pExpand);
- if (RT_SUCCESS(rc))
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
- else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
- fIoInProgress = true;
- else
- {
- VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
- break;
- }
-
- } while (0);
-
- if (!fIoInProgress)
- vhdAsyncExpansionComplete(pImage, pIoCtx, pExpand);
- else
- rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
- }
- else
- {
- /*
- * Calculate the real offset in the file.
- */
- uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
-
- /* Read in the block's bitmap. */
- PVDMETAXFER pMetaXfer;
- rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pImage->pStorage,
- ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
- pImage->pu8Bitmap,
- pImage->cbDataBlockBitmap, pIoCtx,
- &pMetaXfer, NULL, NULL);
- if (RT_SUCCESS(rc))
- {
- vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer);
-
- /* Write data. */
- rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pImage->pStorage,
- uVhdOffset, pIoCtx, cbWrite,
- NULL, NULL);
- if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
- {
- bool fChanged = false;
-
- /* Set the bits for all sectors having been written. */
- for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++)
- {
- fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex);
- cBATEntryIndex++;
- }
-
- /* Only write the bitmap if it was changed. */
- if (fChanged)
- {
- /*
- * Write the bitmap back.
- *
- * @note We don't have a completion callback here because we
- * can't do anything if the write fails for some reason.
- * The error will propagated to the device/guest
- * by the generic VD layer already and we don't need
- * to rollback anything here.
- */
- rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage,
- ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
- pImage->pu8Bitmap,
- pImage->cbDataBlockBitmap,
- pIoCtx, NULL, NULL);
- }
- }
- }
- }
- }
- else
- rc = vdIfIoIntFileWriteUserAsync(pImage->pIfIo, pImage->pStorage,
- uOffset, pIoCtx, cbWrite, NULL, NULL);
-
- if (pcbWriteProcess)
- *pcbWriteProcess = cbWrite;
-
- /* Stay on the safe side. Do not run the risk of confusing the higher
- * level, as that can be pretty lethal to image consistency. */
- *pcbPreRead = 0;
- *pcbPostRead = 0;
-
- return rc;
-}
-
-/** @copydoc VBOXHDDBACKEND::pfnAsyncFlush */
-static int vhdAsyncFlush(void *pBackendData, PVDIOCTX pIoCtx)
-{
- PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
-
- /* No need to write anything here. Data is always updated on a write. */
- return vdIfIoIntFileFlushAsync(pImage->pIfIo, pImage->pStorage,
- pIoCtx, NULL, NULL);
-}
-
/** @copydoc VBOXHDDBACKEND::pfnCompact */
static int vhdCompact(void *pBackendData, unsigned uPercentStart,
unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
@@ -2662,7 +2462,7 @@ static int vhdCompact(void *pBackendData, unsigned uPercentStart,
if (pfnParentRead)
{
pvParent = RTMemTmpAlloc(pImage->cbDataBlock);
- AssertBreakStmt(VALID_PTR(pvBuf), rc = VERR_NO_MEMORY);
+ AssertBreakStmt(VALID_PTR(pvParent), rc = VERR_NO_MEMORY);
}
pvBuf = RTMemTmpAlloc(pImage->cbDataBlock);
AssertBreakStmt(VALID_PTR(pvBuf), rc = VERR_NO_MEMORY);
@@ -2727,7 +2527,7 @@ static int vhdCompact(void *pBackendData, unsigned uPercentStart,
/* Block present in image file, read relevant data. */
uint64_t u64Offset = ((uint64_t)paBat[i] + pImage->cDataBlockBitmapSectors) * VHD_SECTOR_SIZE;
rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
- u64Offset, pvBuf, pImage->cbDataBlock, NULL);
+ u64Offset, pvBuf, pImage->cbDataBlock);
if (RT_FAILURE(rc))
break;
@@ -2791,14 +2591,14 @@ static int vhdCompact(void *pBackendData, unsigned uPercentStart,
uint64_t u64Offset = (uint64_t)uBlockUsedPos * cbBlock
+ (offBlocksStart * VHD_SECTOR_SIZE);
rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
- u64Offset, pvBuf, cbBlock, NULL);
+ u64Offset, pvBuf, cbBlock);
if (RT_FAILURE(rc))
break;
u64Offset = (uint64_t)i * cbBlock
+ (offBlocksStart * VHD_SECTOR_SIZE);
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
- u64Offset, pvBuf, cbBlock, NULL);
+ u64Offset, pvBuf, cbBlock);
if (RT_FAILURE(rc))
break;
@@ -2953,18 +2753,18 @@ static int vhdResize(void *pBackendData, uint64_t cbSize,
{
/* Read data and append to the end of the image. */
rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage,
- offStartDataNew, pvBuf, cbBlock, NULL);
+ offStartDataNew, pvBuf, cbBlock);
if (RT_FAILURE(rc))
break;
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
- pImage->uCurrentEndOfFile, pvBuf, cbBlock, NULL);
+ pImage->uCurrentEndOfFile, pvBuf, cbBlock);
if (RT_FAILURE(rc))
break;
/* Zero out the old block area. */
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
- offStartDataNew, pvZero, cbBlock, NULL);
+ offStartDataNew, pvZero, cbBlock);
if (RT_FAILURE(rc))
break;
@@ -3015,7 +2815,7 @@ static int vhdResize(void *pBackendData, uint64_t cbSize,
rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage,
pImage->uBlockAllocationTableOffset,
pImage->pBlockAllocationTable,
- cBlocksNew * sizeof(uint32_t), NULL);
+ cBlocksNew * sizeof(uint32_t));
}
if (RT_SUCCESS(rc))
@@ -3032,7 +2832,7 @@ static int vhdResize(void *pBackendData, uint64_t cbSize,
/* Update header information in base image file. */
pImage->fDynHdrNeedsUpdate = true;
- vhdFlush(pImage);
+ vhdFlushImage(pImage);
}
/* Same size doesn't change the image at all. */
@@ -3099,7 +2899,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
}
rc = vdIfIoIntFileReadSync(pIfIo, pStorage, cbFile - sizeof(VHDFooter),
- &vhdFooter, sizeof(VHDFooter), NULL);
+ &vhdFooter, sizeof(VHDFooter));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, rc, RT_SRC_POS, "Failed to read footer of image");
@@ -3110,7 +2910,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
{
/* Dynamic images have a backup at the beginning of the image. */
rc = vdIfIoIntFileReadSync(pIfIo, pStorage, 0,
- &vhdFooter, sizeof(VHDFooter), NULL);
+ &vhdFooter, sizeof(VHDFooter));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, rc, RT_SRC_POS, "Failed to read header of image");
@@ -3185,7 +2985,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
}
rc = vdIfIoIntFileReadSync(pIfIo, pStorage, offDynamicDiskHeader,
- &dynamicDiskHeader, sizeof(VHDDynamicDiskHeader), NULL);
+ &dynamicDiskHeader, sizeof(VHDDynamicDiskHeader));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
@@ -3232,7 +3032,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
}
rc = vdIfIoIntFileReadSync(pIfIo, pStorage, offBat, paBat,
- cBatEntries * sizeof(uint32_t), NULL);
+ cBatEntries * sizeof(uint32_t));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
@@ -3285,7 +3085,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
}
if ( paBat[i] != UINT32_C(0xffffffff)
- && ASMBitTestAndSet(pu32BlockBitmap, (paBat[i] - idxMinBlock) / (cbBlock / VHD_SECTOR_SIZE)))
+ && ASMBitTestAndSet(pu32BlockBitmap, (uint32_t)((paBat[i] - idxMinBlock) / (cbBlock / VHD_SECTOR_SIZE))))
{
vdIfErrorMessage(pIfError, "Entry %u points to an already referenced data block, clearing\n",
i);
@@ -3309,7 +3109,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
vdIfErrorMessage(pIfError, "Writing repaired block allocation table...\n");
rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, offBat, paBat,
- cBatEntries * sizeof(uint32_t), NULL);
+ cBatEntries * sizeof(uint32_t));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
@@ -3325,7 +3125,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
vdIfErrorMessage(pIfError, "Writing repaired dynamic disk header...\n");
rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, offDynamicDiskHeader, &dynamicDiskHeader,
- sizeof(VHDDynamicDiskHeader), NULL);
+ sizeof(VHDDynamicDiskHeader));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
@@ -3343,7 +3143,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
{
/* Write backup at image beginning. */
rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, 0, &vhdFooter,
- sizeof(VHDFooter), NULL);
+ sizeof(VHDFooter));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
@@ -3354,7 +3154,7 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
}
rc = vdIfIoIntFileWriteSync(pIfIo, pStorage, offFooter, &vhdFooter,
- sizeof(VHDFooter), NULL);
+ sizeof(VHDFooter));
if (RT_FAILURE(rc))
{
rc = vdIfError(pIfError, VERR_VD_IMAGE_REPAIR_IMPOSSIBLE, RT_SRC_POS,
@@ -3375,7 +3175,11 @@ static DECLCALLBACK(int) vhdRepair(const char *pszFilename, PVDINTERFACE pVDIfsD
RTMemFree(pu32BlockBitmap);
if (pStorage)
- vdIfIoIntFileClose(pIfIo, pStorage);
+ {
+ int rc2 = vdIfIoIntFileClose(pIfIo, pStorage);
+ if (RT_SUCCESS(rc))
+ rc = rc2; /* Propagate status code only when repairing the image was successful. */
+ }
LogFlowFunc(("returns %Rrc\n", rc));
return rc;
@@ -3414,8 +3218,12 @@ VBOXHDDBACKEND g_VhdBackend =
vhdWrite,
/* pfnFlush */
vhdFlush,
+ /* pfnDiscard */
+ NULL,
/* pfnGetVersion */
vhdGetVersion,
+ /* pfnGetSectorSize */
+ vhdGetSectorSize,
/* pfnGetSize */
vhdGetSize,
/* pfnGetFileSize */
@@ -3466,12 +3274,6 @@ VBOXHDDBACKEND g_VhdBackend =
vhdGetParentFilename,
/* pfnSetParentFilename */
vhdSetParentFilename,
- /* pfnAsyncRead */
- vhdAsyncRead,
- /* pfnAsyncWrite */
- vhdAsyncWrite,
- /* pfnAsyncFlush */
- vhdAsyncFlush,
/* pfnComposeLocation */
genericFileComposeLocation,
/* pfnComposeName */
@@ -3480,10 +3282,6 @@ VBOXHDDBACKEND g_VhdBackend =
vhdCompact,
/* pfnResize */
vhdResize,
- /* pfnDiscard */
- NULL,
- /* pfnAsyncDiscard */
- NULL,
/* pfnRepair */
vhdRepair
};