DrvVD.cpp revision c97989161fbe75bc14cea477a5443bbf474dd3ad
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VBox storage devices:
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Media implementation for VBox disk container
c97989161fbe75bc14cea477a5443bbf474dd3advboxsync * Copyright (C) 2006-2007 innotek GmbH
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * available from http://www.virtualbox.org. This file is free software;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * General Public License as published by the Free Software Foundation,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * If you received this file as part of a commercial VirtualBox
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * distribution, then only the terms of your commercial VirtualBox
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * license agreement apply instead of the previous paragraph.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Header files *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Defined types, constants and macros *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** Converts a pointer to VDIDISK::IMedia to a PVBOXDISK. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) )
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** Converts a pointer to PDMDRVINS::IBase to a PVBOXDISK. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync ( PDMINS2DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) )
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VBox disk container media main structure, private part.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsynctypedef struct VBOXDISK
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The VBox disk container. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The media interface. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Pointer to the driver instance. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Name of the image format backend. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** Flag whether suspend has changed image open mode to read only. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Error reporting callback *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic void vdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pDrvIns->pDrvHlp->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Media interface methods *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnRead */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdRead(PPDMIMEDIA pInterface,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log2(("%s: off=%#llx pvBuf=%p cbRead=%d %.*Vhxd\n", __FUNCTION__,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnWrite */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdWrite(PPDMIMEDIA pInterface,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d %.*Vhxd\n", __FUNCTION__,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = VDWrite(pData->pDisk, off, pvBuf, cbWrite);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnFlush */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdFlush(PPDMIMEDIA pInterface)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnGetSize */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(uint64_t) vdGetSize(PPDMIMEDIA pInterface)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnIsReadOnly */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(bool) vdIsReadOnly(PPDMIMEDIA pInterface)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnBiosGetGeometry */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdBiosGetGeometry(PPDMIMEDIA pInterface,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = VDGetGeometry(pData->pDisk, pcCylinders, pcHeads, pcSectors);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log(("%s: geometry not available.\n", __FUNCTION__));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("%s: returns %Vrc (CHS=%d/%d/%d)\n", __FUNCTION__,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnBiosSetGeometry */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdBiosSetGeometry(PPDMIMEDIA pInterface,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = VDSetGeometry(pData->pDisk, cCylinders, cHeads, cSectors);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnBiosGetTranslation */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdBiosGetTranslation(PPDMIMEDIA pInterface,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = VDGetTranslation(pData->pDisk, penmTranslation);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("%s: returns %Vrc (%d)\n", __FUNCTION__, rc, *penmTranslation));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnBiosSetTranslation */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdBiosSetTranslation(PPDMIMEDIA pInterface,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = VDSetTranslation(pData->pDisk, enmTranslation);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("%s: returns %Vrc (%d)\n", __FUNCTION__, rc, enmTranslation));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIMEDIA::pfnGetUuid */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogFlow(("%s: returns %Vrc ({%Vuuid})\n", __FUNCTION__, rc, pUuid));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Base interface methods *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/** @copydoc PDMIBASE::pfnQueryInterface */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(void *) vdQueryInterface(PPDMIBASE pInterface,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*******************************************************************************
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync* Driver methods *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync*******************************************************************************/
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Construct a VBox disk media driver instance.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @returns VBox status.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pDrvIns The driver instance data.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * If the registration structure is needed, pDrvIns->pDrvReg points to it.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * of the driver instance. It's also found in pDrvIns->pCfgHandle as it's expected
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * to be used frequently in this function.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(int) vdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync char *pszName; /**< The path of the disk image file. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync bool fReadOnly; /**< True if the media is readonly. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync bool fHonorZeroWrites; /**< True if zero blocks should be written. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Init the static parts.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pDrvIns->IBase.pfnQueryInterface = vdQueryInterface;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* IMedia */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pData->IMedia.pfnBiosGetGeometry = vdBiosGetGeometry;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pData->IMedia.pfnBiosSetGeometry = vdBiosSetGeometry;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pData->IMedia.pfnBiosGetTranslation = vdBiosGetTranslation;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pData->IMedia.pfnBiosSetTranslation = vdBiosSetTranslation;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Validate configuration and find all parent images.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * It's sort of up side down from the image dependency tree.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync unsigned iLevel = 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* Toplevel configuration contains the format backend name and
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * full image open information. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "Path\0ReadOnly\0HonorZeroWrites\0");
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* All other image configurations only contain image name. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Open the images.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = CFGMR3QueryString(pCfgHandle, "Format", &pData->szFormat[0],
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* Default disk image format is VMDK. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync strncpy(&pData->szFormat[0], "VMDK", sizeof(pData->szFormat));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync pData->szFormat[sizeof(pData->szFormat) - 1] = '\0';
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = VDCreate(pData->szFormat, vdErrorCallback, pDrvIns, &pData->pDisk);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* Error message is already set correctly. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Read the image configuration.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = CFGMR3QueryBool(pCurNode, "ReadOnly", &fReadOnly);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync rc = CFGMR3QueryBool(pCfgHandle, "HonorZeroWrites", &fHonorZeroWrites);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Open the image.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync VDIsReadOnly(pData->pDisk) ? "read-only" : "read-write"));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AssertMsgFailed(("Failed to open image '%s' rc=%Vrc\n", pszName, rc));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Destruct a driver instance.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * resources can be freed correctly.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pDrvIns The driver instance data.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(void) vdDestruct(PPDMDRVINS pDrvIns)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * When the VM has been suspended we'll change the image mode to read-only
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * so that main and others can read the VDIs. This is important when
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * saving state and so forth.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pDrvIns The driver instance data.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(void) vdSuspend(PPDMDRVINS pDrvIns)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = VDGetOpenFlags(pData->pDisk, &uOpenFlags);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Before the VM resumes we'll have to undo the read-only mode change
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * done in vdSuspend.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * @param pDrvIns The driver instance data.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic DECLCALLBACK(void) vdResume(PPDMDRVINS pDrvIns)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int rc = VDGetOpenFlags(pData->pDisk, &uOpenFlags);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * VBox disk container media driver registration record.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* u32Version */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* szDriverName */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pszDescription */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "Generic VBox disk media driver.",
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* fFlags */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* fClass. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* cMaxInstances */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* cbInstance */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnConstruct */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnDestruct */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnIOCtl */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnPowerOn */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnReset */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnSuspend */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnResume */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* pfnDetach */