VHD.cpp revision c4683f6e02044ce17c237d67c47cadd169c82ef2
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * VHD Disk image, Core Code.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Copyright (C) 2006-2010 Oracle Corporation
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * available from http://www.virtualbox.org. This file is free software;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * you can redistribute it and/or modify it under the terms of the GNU
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * General Public License (GPL) as published by the Free Software
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/*******************************************************************************
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync* Header Files *
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync*******************************************************************************/
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/* This is common to all VHD disk types and is located at the end of the image */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsynctypedef struct VHDFooter
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/* this really is spelled with only one n */
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync#define VHD_FOOTER_DATA_OFFSET_FIXED UINT64_C(0xffffffffffffffff)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/* Header for expanding disk images. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync VHDPLE ParentLocatorEntry[VHD_MAX_LOCATOR_ENTRIES];
c80170800394cbf2746e3136b41886c2d11617aevboxsync * Complete VHD image data structure.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsynctypedef struct VHDIMAGE
a494f8cb9c33df07e260ac05855653c130f7b057vboxsync /** Image file name. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Opaque storage handle. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** I/O interface. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** I/O interface callbacks. */
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync /** Pointer to the per-disk VD interface list. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Pointer to the per-image VD interface list. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Error interface. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Error interface callback table. */
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync /** Open flags passed by VBoxHDD layer. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Image flags defined during creation or determined during open. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Total size of the image. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Physical geometry of this image. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Logical geometry of this image. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Image UUID. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Parent image UUID. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Parent's time stamp at the time of image creation. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Relative path to the parent image. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** The Block Allocation Table. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Number of entries in the table. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Size of one data block. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Sectors per data block. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Length of the sector bitmap in bytes. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** A copy of the disk footer. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Current end offset of the file (without the disk footer). */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Size of the data block bitmap in sectors. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Start of the block allocation table. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Buffer to hold block's bitmap for bit search operations. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Offset to the next data structure (dynamic disk header). */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Flag to force dynamic disk header update. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Structure tracking the expansion process of the image
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * for async access.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Flag indicating the status of each step. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** The index in the block allocation table which is written. */
c80170800394cbf2746e3136b41886c2d11617aevboxsync /** Big endian representation of the block index
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * which is written in the BAT. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Old end of the file - used for rollback in case of an error. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /** Sector bitmap written to the new block - variable in size. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Flag defines
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/** All steps completed successfully. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/** All steps completed (no success indicator) */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/** Every status field has 2 bits so we can encode 4 steps in one byte. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync#define VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT 0x00
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Helper macros to get and set the status field.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync (((fFlags) >> (cShift)) & VHDIMAGEEXPAND_STATUS_MASK)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync#define VHDIMAGEEXPAND_STATUS_SET(fFlags, cShift, uVal) \
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync ASMAtomicOrU32(&(fFlags), ((uVal) & VHDIMAGEEXPAND_STATUS_MASK) << (cShift))
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/*******************************************************************************
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync* Static Variables *
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync*******************************************************************************/
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/** NULL-terminated array of supported file extensions. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncstatic const VDFILEEXTENSION s_aVhdFileExtensions[] =
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/*******************************************************************************
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync* Internal Functions *
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync*******************************************************************************/
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Internal: signal an error to the frontend.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdError(PVHDIMAGE pImage, int rc, RT_SRC_POS_DECL,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync const char *pszFormat, ...)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Internal: signal an informational message to the frontend.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdMessage(PVHDIMAGE pImage, const char *pszFormat, ...)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = pImage->pInterfaceErrorCallbacks->pfnMessage(pImage->pInterfaceError->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileOpen(PVHDIMAGE pImage, const char *pszFilename,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnOpen(pImage->pInterfaceIO->pvUser,
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync return pImage->pInterfaceIOCallbacks->pfnClose(pImage->pInterfaceIO->pvUser,
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsyncDECLINLINE(int) vhdFileDelete(PVHDIMAGE pImage, const char *pszFilename)
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync return pImage->pInterfaceIOCallbacks->pfnDelete(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileMove(PVHDIMAGE pImage, const char *pszSrc,
a494f8cb9c33df07e260ac05855653c130f7b057vboxsync return pImage->pInterfaceIOCallbacks->pfnMove(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileGetFreeSpace(PVHDIMAGE pImage, const char *pszFilename,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnGetFreeSpace(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileGetModificationTime(PVHDIMAGE pImage,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnGetModificationTime(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileGetSize(PVHDIMAGE pImage, uint64_t *pcbSize)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnGetSize(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileSetSize(PVHDIMAGE pImage, uint64_t cbSize)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileWriteSync(PVHDIMAGE pImage, uint64_t uOffset,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnWriteSync(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileReadSync(PVHDIMAGE pImage, uint64_t uOffset,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnReadSync(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
ad27e1d5e48ca41245120c331cc88b50464813cevboxsyncDECLINLINE(int) vhdFileReadUserAsync(PVHDIMAGE pImage, uint64_t uOffset,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileWriteUserAsync(PVHDIMAGE pImage, uint64_t uOffset,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileReadMetaAsync(PVHDIMAGE pImage, uint64_t uOffset,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser,
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsyncDECLINLINE(int) vhdFileWriteMetaAsync(PVHDIMAGE pImage, uint64_t uOffset,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync return pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(int) vhdFileFlushAsync(PVHDIMAGE pImage, PVDIOCTX pIoCtx,
c80170800394cbf2746e3136b41886c2d11617aevboxsync return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncDECLINLINE(void) vhdFileMetaXferRelease(PVHDIMAGE pImage, PVDMETAXFER pMetaXfer)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Internal: Compute and update header checksum.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncstatic uint32_t vhdChecksum(void *pHeader, uint32_t cbSize)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Internal: Convert filename to UTF16 with appropriate endianness.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncstatic int vhdFilenameToUtf16(const char *pszFilename, uint16_t *pu16Buf,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync for (unsigned i = 0; i < cTmp16Len; i++)
a494f8cb9c33df07e260ac05855653c130f7b057vboxsync memcpy(pu16Buf, tmp16, cTmp16Len * sizeof(*tmp16));
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync *pcbActualSize = (uint32_t)(cTmp16Len * sizeof(*tmp16));
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync * Internal: Update one locator entry.
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsyncstatic int vhdLocatorUpdate(PVHDIMAGE pImage, PVHDPLE pLocator, const char *pszFilename)
a494f8cb9c33df07e260ac05855653c130f7b057vboxsync uint32_t cb, cbMaxLen = RT_BE2H_U32(pLocator->u32DataSpace) * VHD_SECTOR_SIZE;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Update plain relative name. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Update plain absolute name. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = RTPathAbs(pszFilename, (char *)pvBuf, cbMaxLen);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pLocator->u32DataLength = RT_H2BE_U32((uint32_t)strlen((const char *)pvBuf));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Update unicode relative name. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = vhdFilenameToUtf16(pszFilename, (uint16_t *)pvBuf, cbMaxLen, &cb, false);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Update unicode absolute name. */
701a45600245e42829e1187817299e812eebdec5vboxsync rc = vhdFilenameToUtf16(pszTmp, (uint16_t *)pvBuf, cbMaxLen, &cb, false);
ebbcebe494da0e177ffb36f2a60fddb9e1816aadvboxsync rc = vhdFileWriteSync(pImage, RT_BE2H_U64(pLocator->u64DataOffset),
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pvBuf, RT_BE2H_U32(pLocator->u32DataSpace) * VHD_SECTOR_SIZE,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Internal: Update dynamic disk header from VHDIMAGE.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = vhdFileReadSync(pImage, pImage->u64DataOffset, &ddh, sizeof(ddh), NULL);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (memcmp(ddh.Cookie, VHD_DYNAMIC_DISK_HEADER_COOKIE, VHD_DYNAMIC_DISK_HEADER_COOKIE_SIZE) != 0)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Update parent's timestamp. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync ddh.ParentTimeStamp = RT_H2BE_U32(pImage->u32ParentTimeStamp);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Update parent's filename. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = vhdFilenameToUtf16(RTPathFilename(pImage->pszParentFilename),
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync ddh.ParentUnicodeName, sizeof(ddh.ParentUnicodeName) - 1, NULL, true);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Update parent's locators. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync for (i = 0; i < VHD_MAX_LOCATOR_ENTRIES; i++)
return rc;
return rc;
pImage->vhdFooterCopy.Checksum = RT_H2BE_U32(vhdChecksum(&pImage->vhdFooterCopy, sizeof(VHDFooter)));
return rc;
return VINF_SUCCESS;
return VERR_NO_MEMORY;
return rc;
if (pImage)
if (!fDelete)
return rc;
#ifdef RT_ARCH_AMD64
bool fIoInProgress = false;
static int vhdAsyncExpansionStepCompleted(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq, unsigned iStep)
return VERR_VD_ASYNC_IO_IN_PROGRESS;
static int vhdAsyncExpansionDataBlockBitmapComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
return vhdAsyncExpansionStepCompleted(pBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT);
static int vhdAsyncExpansionDataComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
return vhdAsyncExpansionStepCompleted(pBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT);
static int vhdAsyncExpansionBatUpdateComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
return vhdAsyncExpansionStepCompleted(pBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_BAT_STATUS_SHIFT);
static int vhdAsyncExpansionFooterUpdateComplete(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
return vhdAsyncExpansionStepCompleted(pBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT);
NULL);
if (memcmp(vhdDynamicDiskHeader.Cookie, VHD_DYNAMIC_DISK_HEADER_COOKIE, VHD_DYNAMIC_DISK_HEADER_COOKIE_SIZE))
return VERR_INVALID_PARAMETER;
AssertMsg(!(pImage->cbDataBlock % VHD_SECTOR_SIZE), ("%s: Data block size is not a multiple of %!\n", __FUNCTION__, VHD_SECTOR_SIZE));
return VERR_NO_MEMORY;
pBlockAllocationTable = (uint32_t *)RTMemAllocZ(pImage->cBlockAllocationTableEntries * sizeof(uint32_t));
if (!pBlockAllocationTable)
return VERR_NO_MEMORY;
NULL);
pImage->pBlockAllocationTable = (uint32_t *)RTMemAllocZ(pImage->cBlockAllocationTableEntries * sizeof(uint32_t));
return VERR_NO_MEMORY;
return rc;
return rc;
return VERR_VD_VHD_INVALID_HEADER;
return VERR_NOT_IMPLEMENTED;
return rc;
DECLINLINE(bool) vhdBlockBitmapSectorSet(PVHDIMAGE pImage, uint8_t *pu8Bitmap, uint32_t cBlockBitmapEntry)
static uint32_t vhdAllocateParentLocators(PVHDIMAGE pImage, VHDDynamicDiskHeader *pDDH, uint64_t u64Offset)
pLocator++;
pLocator++;
pLocator++;
int rc;
return vhdError(pImage, VERR_NO_MEMORY, RT_SRC_POS, N_("VHD: cannot allocate memory for bitmap storage"));
pImage->cBlockAllocationTableEntries = (uint32_t)((cbSize + pImage->cbDataBlock - 1) / pImage->cbDataBlock); /* Align table to the block size. */
u32BlockAllocationTableSectors = (pImage->cBlockAllocationTableEntries * sizeof(uint32_t) + VHD_SECTOR_SIZE - 1) / VHD_SECTOR_SIZE;
pImage->pBlockAllocationTable = (uint32_t *)RTMemAllocZ(pImage->cBlockAllocationTableEntries * sizeof(uint32_t));
pImage->uCurrentEndOfFile = pImage->uBlockAllocationTableOffset + u32BlockAllocationTableSectors * VHD_SECTOR_SIZE;
if (!pvTmp)
return vhdError(pImage, VERR_NO_MEMORY, RT_SRC_POS, N_("VHD: cannot set the file size for '%s'"), pImage->pszFilename);
return vhdError(pImage, rc, RT_SRC_POS, N_("VHD: cannot set the file size for '%s'"), pImage->pszFilename);
DynamicDiskHeader.Checksum = RT_H2BE_U32(vhdChecksum(&DynamicDiskHeader, sizeof(DynamicDiskHeader)));
return vhdError(pImage, rc, RT_SRC_POS, N_("VHD: cannot write dynamic disk header to image '%s'"), pImage->pszFilename);
NULL);
return vhdError(pImage, rc, RT_SRC_POS, N_("VHD: cannot write BAT to image '%s'"), pImage->pszFilename);
return rc;
unsigned uOpenFlags,
int rc;
#ifdef RT_OS_DARWIN
vhdError(pImage, rc, RT_SRC_POS, N_("VHD: cannot set the file size for '%s'"), pImage->pszFilename);
goto out;
if (pfnProgress)
goto out;
vhdError(pImage, rc, RT_SRC_POS, N_("VHD: cannot write footer to image '%s'"), pImage->pszFilename);
goto out;
vhdError(pImage, rc, RT_SRC_POS, N_("VHD: cannot write a copy of footer to image '%s'"), pImage->pszFilename);
goto out;
out:
return rc;
LogFlowFunc(("pszFilename=\"%s\" pVDIfsDisk=%#p pVDIfsImage=%#p\n", pszFilename, pVDIfsDisk, pVDIfsImage));
int rc;
&pStorage);
goto out;
&cbFile);
goto out;
out:
return rc;
LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, ppBackendData));
goto out;
|| !*pszFilename)
goto out;
if (!pImage)
goto out;
out:
return rc;
LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p ppBackendData=%#p", pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, ppBackendData));
if (pIfProgress)
if (pCbProgress)
return rc;
if (!pImage)
return rc;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
goto out;
out:
return rc;
if ( !pImage
|| !pszFilename
|| !*pszFilename)
goto out;
goto out;
goto out;
goto out;
out:
return rc;
int rc;
return rc;
LogFlowFunc(("pBackendData=%p uOffset=%#llx pvBuf=%p cbBuf=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbActuallyRead));
goto out;
LogFlowFunc(("cBlockAllocationTableEntry=%u cBatEntryIndex=%u\n", cBlockAllocationTableEntry, cBATEntryIndex));
LogFlowFunc(("BlockAllocationEntry=%u\n", pImage->pBlockAllocationTable[cBlockAllocationTableEntry]));
goto out;
uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
NULL);
cSectors++;
cSectors++;
if (pcbActuallyRead)
out:
return rc;
LogFlowFunc(("pBackendData=%#p uOffset=%llu pvBuf=%#p cbBuf=%zu pcbWriteProcess=%#p\n", pBackendData, uOffset, pvBuf, cbBuf, pcbWriteProcess));
LogFlowFunc(("pBackendData=%p uOffset=%llu pvBuf=%p cbBuf=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
if (pcbWriteProcess)
goto out;
if (!pNewBlock)
goto out;
pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
NULL);
bool fChanged = false;
if (fChanged)
NULL);
if (pcbWriteProcess)
*pcbPreRead = 0;
*pcbPostRead = 0;
out:
return rc;
int rc;
return rc;
unsigned ver = 0;
if (pImage)
return ver;
return cb;
return cb;
int rc;
if (pImage)
LogFlowFunc(("returns %Rrc (CHS=%u/%u/%u)\n", rc, pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors));
return rc;
LogFlowFunc(("pBackendData=%#p pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pBackendData, pPCHSGeometry, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
int rc;
if (pImage)
goto out;
out:
return rc;
int rc;
if (pImage)
LogFlowFunc(("returns %Rrc (CHS=%u/%u/%u)\n", rc, pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors));
return rc;
int rc;
if (pImage)
goto out;
out:
return rc;
unsigned uImageFlags;
if (pImage)
uImageFlags = 0;
return uImageFlags;
unsigned uOpenFlags;
if (pImage)
uOpenFlags = 0;
return uOpenFlags;
int rc;
if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
goto out;
goto out;
out:
return rc;
LogFlowFunc(("pBackendData=%#p pszComment=%#p cbComment=%zu\n", pBackendData, pszComment, cbComment));
int rc;
if (pImage)
return rc;
int rc;
if (pImage)
return rc;
int rc;
if (pImage)
return rc;
int rc;
if (pImage)
pImage->vhdFooterCopy.Checksum = RT_H2BE_U32(vhdChecksum(&pImage->vhdFooterCopy, sizeof(VHDFooter)));
return rc;
int rc;
if (pImage)
return rc;
int rc;
if (pImage)
return rc;
int rc;
if (pImage)
return rc;
return rc;
int rc;
if (pImage)
return rc;
int rc;
if (pImage)
return rc;
if (pImage)
if (pImage)
return rc;
if (pImage)
return rc;
if (pImage)
return rc;
if (pImage)
return rc;
if (pImage)
return rc;
LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbRead=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
return VERR_INVALID_PARAMETER;
LogFlowFunc(("cBlockAllocationTableEntry=%u cBatEntryIndex=%u\n", cBlockAllocationTableEntry, cBATEntryIndex));
LogFlowFunc(("BlockAllocationEntry=%u\n", pImage->pBlockAllocationTable[cBlockAllocationTableEntry]));
return VERR_VD_BLOCK_FREE;
uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
cSectors++;
cSectors++;
if (pcbActuallyRead)
return rc;
LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
if (pcbWriteProcess)
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);
VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
fIoInProgress = true;
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);
pExpand);
VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
fIoInProgress = true;
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);
pExpand);
VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
fIoInProgress = true;
VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
pExpand);
VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
fIoInProgress = true;
VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
if (!fIoInProgress)
uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
bool fChanged = false;
if (fChanged)
if (pcbWriteProcess)
*pcbPreRead = 0;
*pcbPostRead = 0;
return rc;
if (pIfParentState)
if (pCbParentState)
if (pIfProgress)
if (pCbProgress)
if (pfnParentRead)
unsigned cBlocksAllocated = 0;
unsigned cBlocksToMove = 0;
for (unsigned i = 0; i < cBlocks; i++)
if (paBat[i] != ~0U)
if (!cBlocksAllocated)
for (unsigned i = 0; i < cBlocksAllocated; i++)
paBlocks[i] = ~0U;
for (unsigned i = 0; i < cBlocks; i++)
if (paBat[i] != ~0U)
for (unsigned i = 0; i < cBlocks; i++)
if (paBat[i] != ~0U)
paBat[i] = ~0;
else if (pfnParentRead)
paBat[i] = ~0U;
unsigned cBlocksMoved = 0;
size_t cbBlock = pImage->cbDataBlock + pImage->cbDataBlockBitmap; /** < Size of whole block containing the bitmap and the user data. */
/* Allocate data buffer to hold the data block and allocation bitmap in front of the actual data. */
for (unsigned i = 0; i < cBlocksAllocated; i++)
if (uBlock == ~0U)
unsigned uBlockData = ~0U;
if (uBlockUsedPos == i)
cBlocksMoved++;
if (paBlocks)
if (pvParent)
if (pvBuf)
return rc;
if (pIfProgress)
if (pCbProgress)
unsigned cBlocksAllocated = 0;
size_t cbBlock = pImage->cbDataBlock + pImage->cbDataBlockBitmap; /** < Size of a block including the sector bitmap. */
uint32_t cBlocksNew = cbSize / pImage->cbDataBlock; /** < New number of blocks in the image after the resize */
cBlocksNew++;
uint32_t cBlocksOld = pImage->cBlockAllocationTableEntries; /** < Number of blocks before the resize. */
uint64_t cbBlockspaceNew = RT_ALIGN_32(cBlocksNew * sizeof(uint32_t), VHD_SECTOR_SIZE); /** < Required space for the block array after the resize. */
uint64_t offStartDataNew = RT_ALIGN_32(pImage->uBlockAllocationTableOffset + cbBlockspaceNew, VHD_SECTOR_SIZE); /** < New start offset for block data after the resize */
&& cBlocksAllocated > 0)
cBlocksReloc++;
if (!pvBuf)
if (!pvZero)
for (unsigned i = 0; i < cBlocksReloc; i++)
if (pvBuf)
if (pvZero)
uint32_t *paBlocksNew = (uint32_t *)RTMemRealloc(pImage->pBlockAllocationTable, cBlocksNew * sizeof(uint32_t));
if (paBlocksNew)
return rc;
sizeof(VBOXHDDBACKEND),
NULL,