VirtualBox

Changeset 2358

Show
Ignore:
Timestamp:
04/26/07 18:53:00 (2 years ago)
Author:
vboxsync
Message:

New VMDK code.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/include/VBox/VBoxHDD-new.h

    r2118 r2358  
    111111 
    112112/** 
     113 * Error message callback. 
     114 * 
     115 * @param   pvUser          The opaque data passed on container creation. 
     116 * @param   rc              The VBox error code. 
     117 * @param   RT_SRC_POS_DECL Use RT_SRC_POS. 
     118 * @param   pszFormat       Error message format string. 
     119 * @param   va              Error message arguments. 
     120 */ 
     121typedef DECLCALLBACK(void) FNVDERROR(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va); 
     122/** Pointer to a FNVDERROR(). */ 
     123typedef FNVDERROR *PFNVDERROR; 
     124 
     125 
     126/** 
    113127 * VBox HDD Container main structure. 
    114128 */ 
     
    124138 * @returns VBox status code. 
    125139 * @param   pszBackend      Name of the image file backend to use. 
     140 * @param   pfnError        Callback for setting extended error information. 
     141 * @param   pvErrorUser     Opaque parameter for pfnError. 
    126142 * @param   ppDisk          Where to store the reference to the VBox HDD container. 
    127143 */ 
    128 VBOXDDU_DECL(int) VDCreate(const char *pszBackend, PVBOXHDD *ppDisk); 
     144VBOXDDU_DECL(int) VDCreate(const char *pszBackend, PFNVDERROR pfnError, void *pvErrorUser, PVBOXHDD *ppDisk); 
    129145 
    130146/** 
     
    235251 * are stored in ascending location in the image file. 
    236252 * 
     253 * @todo maybe include this function in VDCopy. 
     254 * 
    237255 * @returns VBox status code. 
    238256 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container. 
     
    271289 * @param   fDelete         If true, delete the image from the host disk. 
    272290 */ 
    273 VBOXDDU_DECL(void) VDClose(PVBOXHDD pDisk, bool fDelete); 
     291VBOXDDU_DECL(int) VDClose(PVBOXHDD pDisk, bool fDelete); 
    274292 
    275293/** 
     
    278296 * @param   pDisk           Pointer to VBox HDD container. 
    279297 */ 
    280 VBOXDDU_DECL(void) VDCloseAll(PVBOXHDD pDisk); 
     298VBOXDDU_DECL(int) VDCloseAll(PVBOXHDD pDisk); 
    281299 
    282300/** 
     
    286304 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container. 
    287305 * @param   pDisk           Pointer to VBox HDD container. 
    288  * @param   off             Offset of first reading byte from start of disk. 
     306 * @param   uOffset         Offset of first reading byte from start of disk. 
    289307 * @param   pvBuf           Pointer to buffer for reading data. 
    290308 * @param   cbRead          Number of bytes to read. 
    291309 */ 
    292 VBOXDDU_DECL(int) VDRead(PVBOXHDD pDisk, uint64_t off, void *pvBuf, unsigned cbRead); 
     310VBOXDDU_DECL(int) VDRead(PVBOXHDD pDisk, uint64_t uOffset, void *pvBuf, size_t cbRead); 
    293311 
    294312/** 
     
    298316 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container. 
    299317 * @param   pDisk           Pointer to VBox HDD container. 
    300  * @param   off             Offset of first writing byte from start of disk. 
     318 * @param   uOffset         Offset of first writing byte from start of disk. 
    301319 * @param   pvBuf           Pointer to buffer for writing data. 
    302320 * @param   cbWrite         Number of bytes to write. 
    303321 */ 
    304 VBOXDDU_DECL(int) VDWrite(PVBOXHDD pDisk, uint64_t off, const void *pvBuf, unsigned cbWrite); 
     322VBOXDDU_DECL(int) VDWrite(PVBOXHDD pDisk, uint64_t uOffset, const void *pvBuf, size_t cbWrite); 
    305323 
    306324/** 
     
    338356 */ 
    339357VBOXDDU_DECL(uint64_t) VDGetSize(PVBOXHDD pDisk); 
    340  
    341 /** 
    342  * Get block size of the VBox HDD container. 
    343  * 
    344  * @returns Virtual disk block size in bytes. 
    345  * @returns 0 if no image is opened in HDD container. 
    346  * @param   pDisk           Pointer to VBox HDD container. 
    347  */ 
    348 VBOXDDU_DECL(unsigned) VDGetBlockSize(PVBOXHDD pDisk); 
    349358 
    350359/** 
     
    501510 * @param   pDisk           Pointer to VBox HDD container. 
    502511 * @param   nImage          Image number, counts from 0. 0 is always base image of container. 
    503  * @param   pUuid           Where to store the image uuid
     512 * @param   pUuid           Where to store the image UUID
    504513 */ 
    505514VBOXDDU_DECL(int) VDGetUuid(PVBOXHDD pDisk, unsigned nImage, PRTUUID pUuid); 
     
    523532 * @param   pDisk           Pointer to VBox HDD container. 
    524533 * @param   nImage          Image number, counts from 0. 0 is always base image of container. 
    525  * @param   pUuid           Where to store the image modification uuid
     534 * @param   pUuid           Where to store the image modification UUID
    526535 */ 
    527536VBOXDDU_DECL(int) VDGetModificationUuid(PVBOXHDD pDisk, unsigned nImage, PRTUUID pUuid); 
     
    545554 * @param   pDisk           Pointer to VBox HDD container. 
    546555 * @param   nImage          Image number, counts from 0. 0 is always base image of the container. 
    547  * @param   pUuid           Where to store the parent image uuid
     556 * @param   pUuid           Where to store the parent image UUID
    548557 */ 
    549558VBOXDDU_DECL(int) VDGetParentUuid(PVBOXHDD pDisk, unsigned nImage, PRTUUID pUuid); 
     
    560569 
    561570 
    562  
    563571/** 
    564572 * Debug helper - dumps all opened images in HDD container into the log file. 
  • trunk/include/iprt/cdefs.h

    r2291 r2358  
    899899 
    900900 
     901/** @def RT_H2LE_U64 
     902 * Converts uint64_t value from host to little endian byte order. */ 
     903#define RT_H2LE_U64(u64) (u64) 
     904 
    901905/** @def RT_H2LE_U32 
    902906 * Converts uint32_t value from host to little endian byte order. */ 
     
    907911#define RT_H2LE_U16(u16) (u16) 
    908912 
     913/** @def RT_LE2H_U64 
     914 * Converts uint64_t value from little endian to host byte order. */ 
     915#define RT_LE2H_U64(u64) (u64) 
     916 
    909917/** @def RT_LE2H_U32 
    910918 * Converts uint32_t value from little endian to host byte order. */ 
     
    916924 
    917925 
     926/** @def RT_H2BE_U64 
     927 * Converts uint64_t value from host to big endian byte order. */ 
     928#define RT_H2BE_U64(u64) RT_MAKE_U64_FROM_U32(RT_H2BE_U32((u64) >> 32), RT_H2BE_U32((u64) & 0xffffffff)) 
     929 
    918930/** @def RT_H2BE_U32 
    919931 * Converts uint32_t value from host to big endian byte order. */ 
     
    923935 * Converts uint16_t value from host to big endian byte order. */ 
    924936#define RT_H2BE_U16(u16) (RT_HIBYTE(u16) | (RT_LOBYTE(u16) << 8)) 
     937 
     938/** @def RT_BE2H_U64 
     939 * Converts uint64_t value from big endian to host byte order. */ 
     940#define RT_BE2H_U64(u64) RT_MAKE_U64_FROM_U32(RT_H2BE_U32((u64) >> 32), RT_H2BE_U32((u64) & 0xffffffff)) 
    925941 
    926942/** @def RT_BE2H_U32 
  • trunk/src/VBox/Devices/Builtins.cpp

    r1965 r2358  
    150150    if (VBOX_FAILURE(rc)) 
    151151        return rc; 
    152     rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvVmdkHDD); 
     152    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvVD); 
    153153    if (VBOX_FAILURE(rc)) 
    154154        return rc; 
  • trunk/src/VBox/Devices/Builtins.h

    r1695 r2358  
    6060extern const PDMDRVREG g_DrvBlock; 
    6161extern const PDMDRVREG g_DrvVBoxHDD; 
    62 extern const PDMDRVREG g_DrvVmdkHDD; 
     62extern const PDMDRVREG g_DrvVD; 
    6363extern const PDMDRVREG g_DrvHostDVD; 
    6464extern const PDMDRVREG g_DrvHostFloppy; 
  • trunk/src/VBox/Devices/Makefile

    r2285 r2358  
    7676endif 
    7777VBoxDDU_SOURCES          = \ 
    78         Storage/VDICore.cpp 
    79 #       Storage/VmdkHDDCore.cpp 
     78        Storage/VBoxHDD-new.cpp \ 
     79        Storage/VDICore.cpp \ 
     80        Storage/VmdkHDDCore.cpp 
    8081VBoxDDU_LIBS             = \ 
    8182        $(LIB_RUNTIME) 
     
    380381        Storage/DrvMediaISO.cpp \ 
    381382        Storage/DrvRawImage.cpp \ 
    382         Storage/VBoxHDD.cpp \ 
    383         Storage/VmdkHDD.cpp 
     383        Storage/DrvVD.cpp \ 
     384        Storage/VBoxHDD.cpp 
    384385 
    385386# -- OS specific -- 
     
    408409        Storage/VBoxHDD.cpp \ 
    409410        Storage/DrvBlock.cpp \ 
    410         Storage/VmdkHDD.cpp \ 
    411411        Storage/DrvMediaISO.cpp \ 
    412412        Storage/DrvRawImage.cpp \ 
    413413        Storage/DrvHostBase.cpp \ 
    414414        Storage/DrvHostDVD.cpp \ 
     415        Storage/DrvVD.cpp \ 
    415416        PC/DrvACPI.cpp \ 
    416417        Network/DrvIntNet.cpp \ 
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r1910 r2358  
     1/** $Id$ */ 
    12/** @file 
    23 * 
    34 * VBox storage devices: 
    4  * VBox VMDK container implementation 
     5 * Media implementation for VBox disk container 
    56 */ 
    67 
     
    1920 * distribution, then only the terms of your commercial VirtualBox 
    2021 * license agreement apply instead of the previous paragraph. 
    21  * 
    22  * -------------------------------------------------------------------- 
    23  * 
    24  * This code is based on: 
    25  * 
    26  * Block driver for the VMDK format 
    27  * 
    28  * Copyright (c) 2004 Fabrice Bellard 
    29  * Copyright (c) 2005 Filip Navara 
    30  * 
    31  * Permission is hereby granted, free of charge, to any person obtaining a copy 
    32  * of this software and associated documentation files (the "Software"), to deal 
    33  * in the Software without restriction, including without limitation the rights 
    34  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
    35  * copies of the Software, and to permit persons to whom the Software is 
    36  * furnished to do so, subject to the following conditions: 
    37  * 
    38  * The above copyright notice and this permission notice shall be included in 
    39  * all copies or substantial portions of the Software. 
    40  * 
    41  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    42  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    43  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
    44  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    45  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
    46  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
    47  * THE SOFTWARE. 
    48  */ 
     22 */ 
     23 
    4924 
    5025/******************************************************************************* 
    51 *   Header Files                                                               * 
     26*   Header files                                                               * 
    5227*******************************************************************************/ 
    53 #define LOG_GROUP LOG_GROUP_DRV_VBOXHDD 
     28#define LOG_GROUP LOG_GROUP_DRV_VD 
     29#include <VBox/VBoxHDD-new.h> 
    5430#include <VBox/pdm.h> 
    5531#include <VBox/mm.h> 
     
    6339#include <iprt/string.h> 
    6440 
    65 #include "vl_vbox.h" 
    6641#include "Builtins.h" 
    6742 
     43 
    6844/******************************************************************************* 
    69 *   Constants And Macros, Structures and Typedefs                              * 
     45*   Defined types, constants and macros                                        * 
    7046*******************************************************************************/ 
    7147 
    72 /** The Sector size. 
    73  * Currently we support only 512 bytes sectors. 
    74  */ 
    75 #define VMDK_GEOMETRY_SECTOR_SIZE    (512) 
    76 /**  512 = 2^^9 */ 
    77 #define VMDK_GEOMETRY_SECTOR_SHIFT   (9) 
    78  
    79 #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') 
    80 #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') 
    81  
    82 #pragma pack(1) 
    83 typedef struct { 
    84     uint32_t version; 
    85     uint32_t flags; 
    86     uint32_t disk_sectors; 
    87     uint32_t granularity; 
    88     uint32_t l1dir_offset; 
    89     uint32_t l1dir_size; 
    90     uint32_t file_sectors; 
    91     uint32_t cylinders; 
    92     uint32_t heads; 
    93     uint32_t sectors_per_track; 
    94 } VMDK3Header; 
    95 #pragma pack() 
    96  
    97 #pragma pack(1) 
    98 typedef struct { 
    99     uint32_t version; 
    100     uint32_t flags; 
    101     int64_t capacity; 
    102     int64_t granularity; 
    103     int64_t desc_offset; 
    104     int64_t desc_size; 
    105     int32_t num_gtes_per_gte; 
    106     int64_t rgd_offset; 
    107     int64_t gd_offset; 
    108     int64_t grain_offset; 
    109     char filler[1]; 
    110     char check_bytes[4]; 
    111 } VMDK4Header; 
    112 #pragma pack() 
    113  
    114 #define L2_CACHE_SIZE 16 
    115  
    116 typedef struct BDRVVmdkState { 
    117     /** File handle. */ 
    118     RTFILE                  File; 
    119  
    120     bool                    fReadOnly; 
    121  
    122     uint64_t                total_sectors; 
    123  
    124     int64_t l1_table_offset; 
    125     int64_t l1_backup_table_offset; 
    126     uint32_t *l1_table; 
    127     uint32_t *l1_backup_table; 
    128     unsigned int l1_size; 
    129     uint32_t l1_entry_sectors; 
    130  
    131     unsigned int l2_size; 
    132     uint32_t *l2_cache; 
    133     uint32_t l2_cache_offsets[L2_CACHE_SIZE]; 
    134     uint32_t l2_cache_counts[L2_CACHE_SIZE]; 
    135  
    136     unsigned int cluster_sectors; 
    137 } BDRVVmdkState; 
    138  
    139  
    140 #define VMDKDISK_SIGNATURE          0x8013ABCD 
     48/** Converts a pointer to VDIDISK::IMedia to a PVBOXDISK. */ 
     49#define PDMIMEDIA_2_VBOXDISK(pInterface) \ 
     50    ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) ) 
     51 
     52/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */ 
     53#define PDMIBASE_2_DRVINS(pInterface) \ 
     54    ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) ) 
     55 
     56/** Converts a pointer to PDMDRVINS::IBase to a PVBOXDISK. */ 
     57#define PDMIBASE_2_VBOXDISK(pInterface) \ 
     58    ( PDMINS2DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) ) 
    14159 
    14260 
    14361/** 
    144  * Harddisk geometry. 
    145  */ 
    146 #pragma pack(1) 
    147 typedef struct VMDKDISKGEOMETRY 
    148 
    149     /** Cylinders. */ 
    150     uint32_t    cCylinders; 
    151     /** Heads. */ 
    152     uint32_t    cHeads; 
    153     /** Sectors per track. */ 
    154     uint32_t    cSectors; 
    155     /** Sector size. (bytes per sector) */ 
    156     uint32_t    cbSector; 
    157 } VMDKDISKGEOMETRY, *PVMDKDISKGEOMETRY; 
    158 #pragma pack() 
    159  
    160 /** 
    161  * VMDK HDD Container main structure, private part. 
    162  */ 
    163 typedef struct VMDKDISK 
    164 
    165     uint32_t        u32Signature; 
    166  
    167     BDRVVmdkState   VmdkState; 
    168  
    169     /** Hard disk geometry. */ 
    170     VMDKDISKGEOMETRY Geometry; 
    171  
     62 * VBox disk container media main structure, private part. 
     63 */ 
     64typedef struct VBOXDISK 
     65
     66    /** The VBox disk container. */ 
     67    PVBOXHDD        pDisk; 
    17268    /** The media interface. */ 
    17369    PDMIMEDIA       IMedia; 
    17470    /** Pointer to the driver instance. */ 
    17571    PPDMDRVINS      pDrvIns; 
    176 } VMDKDISK, *PVMDKDISK; 
    177  
    178  
    179 /** Converts a pointer to VDIDISK::IMedia to a PVMDKDISK. */ 
    180 #define PDMIMEDIA_2_VMDKDISK(pInterface) ( (PVMDKDISK)((uintptr_t)pInterface - RT_OFFSETOF(VMDKDISK, IMedia)) ) 
    181  
    182 /** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */ 
    183 #define PDMIBASE_2_DRVINS(pInterface)   ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) ) 
    184  
    185 /** Converts a pointer to PDMDRVINS::IBase to a PVMDKDISK. */ 
    186 #define PDMIBASE_2_VMDKDISK(pInterface)  ( PDMINS2DATA(PDMIBASE_2_DRVINS(pInterface), PVMDKDISK) ) 
    187  
     72    /** Name of the image format backend. */ 
     73    char            szFormat[16]; 
     74    /** Flag whether suspend has changed image open mode to read only. */ 
     75    bool            fTempReadOnly; 
     76} VBOXDISK, *PVBOXDISK; 
    18877 
    18978/******************************************************************************* 
    190 *   Internal Functions                                                         * 
     79*   Error reporting callback                                                   * 
    19180*******************************************************************************/ 
    192 static DECLCALLBACK(int)  vmdkConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle); 
    193 static DECLCALLBACK(void) vmdkDestruct(PPDMDRVINS pDrvIns); 
    194 static DECLCALLBACK(int)  vmdkRead(PPDMIMEDIA pInterface, 
    195                                   uint64_t off, void *pvBuf, size_t cbRead); 
    196 static DECLCALLBACK(int)  vmdkWrite(PPDMIMEDIA pInterface, 
    197                                    uint64_t off, const void *pvBuf, size_t cbWrite); 
    198 static DECLCALLBACK(int)  vmdkFlush(PPDMIMEDIA pInterface); 
    199 static DECLCALLBACK(uint64_t) vmdkGetSize(PPDMIMEDIA pInterface); 
    200 static DECLCALLBACK(int)  vmdkBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, 
    201                                              uint32_t *pcHeads, uint32_t *pcSectors); 
    202 static DECLCALLBACK(int)  vmdkBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, 
    203                                              uint32_t cHeads, uint32_t cSectors); 
    204 static DECLCALLBACK(int)  vmdkGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid); 
    205 static DECLCALLBACK(bool) vmdkIsReadOnly(PPDMIMEDIA pInterface); 
    206 static DECLCALLBACK(int)  vmdkBiosGetTranslation(PPDMIMEDIA pInterface, 
    207                                                 PPDMBIOSTRANSLATION penmTranslation); 
    208 static DECLCALLBACK(int)  vmdkBiosSetTranslation(PPDMIMEDIA pInterface, 
    209                                                 PDMBIOSTRANSLATION enmTranslation); 
    210 static DECLCALLBACK(void *) vmdkQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface); 
    211  
    212 #if 0 
    213 static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) 
    214 
    215     uint32_t magic; 
    216  
    217     if (buf_size < 4) 
    218         return 0; 
    219     magic = be32_to_cpu(*(uint32_t *)buf); 
    220     if (magic == VMDK3_MAGIC || 
    221         magic == VMDK4_MAGIC) 
    222         return 100; 
    223     else 
    224         return 0; 
    225 
    226 #endif 
    227  
    228 static int vmdk_open(PVMDKDISK pDisk, const char *filename, bool fReadOnly) 
    229 
    230     uint32_t magic, i; 
    231     int l1_size; 
    232  
    233     BDRVVmdkState *s = &pDisk->VmdkState; 
    234  
    235     /* 
    236      * Open the image. 
    237      */ 
    238     s->fReadOnly = fReadOnly; 
    239     int rc = RTFileOpen(&s->File, 
    240                         filename, 
    241                         fReadOnly 
    242                         ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE 
    243                         : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); 
     81 
     82static void vdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) 
     83
     84    PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser; 
     85    pDrvIns->pDrvHlp->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); 
     86
     87 
     88/******************************************************************************* 
     89*   Media interface methods                                                    * 
     90*******************************************************************************/ 
     91 
     92/** @copydoc PDMIMEDIA::pfnRead */ 
     93static DECLCALLBACK(int) vdRead(PPDMIMEDIA pInterface, 
     94                                uint64_t off, void *pvBuf, size_t cbRead) 
     95
     96    LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__, 
     97             off, pvBuf, cbRead)); 
     98    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     99    int rc = VDRead(pData->pDisk, off, pvBuf, cbRead); 
     100    if (VBOX_SUCCESS(rc)) 
     101        Log2(("%s: off=%#llx pvBuf=%p cbRead=%d %.*Vhxd\n", __FUNCTION__, 
     102              off, pvBuf, cbRead, cbRead, pvBuf)); 
     103    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc)); 
     104    return rc; 
     105
     106 
     107/** @copydoc PDMIMEDIA::pfnWrite */ 
     108static DECLCALLBACK(int) vdWrite(PPDMIMEDIA pInterface, 
     109                                 uint64_t off, const void *pvBuf, 
     110                                 size_t cbWrite) 
     111
     112    LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__, 
     113             off, pvBuf, cbWrite)); 
     114    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     115    Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d %.*Vhxd\n", __FUNCTION__, 
     116          off, pvBuf, cbWrite, cbWrite, pvBuf)); 
     117    int rc = VDWrite(pData->pDisk, off, pvBuf, cbWrite); 
     118    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc)); 
     119    return rc; 
     120
     121 
     122/** @copydoc PDMIMEDIA::pfnFlush */ 
     123static DECLCALLBACK(int) vdFlush(PPDMIMEDIA pInterface) 
     124
     125    LogFlow(("%s:\n", __FUNCTION__)); 
     126    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     127    int rc = VDFlush(pData->pDisk); 
     128    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc)); 
     129    return rc; 
     130
     131 
     132/** @copydoc PDMIMEDIA::pfnGetSize */ 
     133static DECLCALLBACK(uint64_t) vdGetSize(PPDMIMEDIA pInterface) 
     134
     135    LogFlow(("%s:\n", __FUNCTION__)); 
     136    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     137    uint64_t cb = VDGetSize(pData->pDisk); 
     138    LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb)); 
     139    return cb; 
     140
     141 
     142/** @copydoc PDMIMEDIA::pfnIsReadOnly */ 
     143static DECLCALLBACK(bool) vdIsReadOnly(PPDMIMEDIA pInterface) 
     144
     145    LogFlow(("%s:\n", __FUNCTION__)); 
     146    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     147    bool f = VDIsReadOnly(pData->pDisk); 
     148    LogFlow(("%s: returns %d\n", __FUNCTION__, f)); 
     149    return f; 
     150
     151 
     152/** @copydoc PDMIMEDIA::pfnBiosGetGeometry */ 
     153static DECLCALLBACK(int) vdBiosGetGeometry(PPDMIMEDIA pInterface, 
     154                                           uint32_t *pcCylinders, 
     155                                           uint32_t *pcHeads, 
     156                                           uint32_t *pcSectors) 
     157
     158    LogFlow(("%s:\n", __FUNCTION__)); 
     159    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     160    int rc = VDGetGeometry(pData->pDisk, pcCylinders, pcHeads, pcSectors); 
    244161    if (VBOX_FAILURE(rc)) 
    245162    { 
    246         if (!fReadOnly) 
    247         { 
    248             /* Try to open image for reading only. */ 
    249             rc = RTFileOpen(&s->File, 
    250                             filename, 
    251                             RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); 
    252             if (VBOX_SUCCESS(rc)) 
    253                 s->fReadOnly = true; 
    254         } 
    255         if (VBOX_FAILURE(rc)) 
    256             return rc; 
    257     } 
    258     rc = RTFileRead(s->File, &magic, sizeof(magic), NULL); 
    259     AssertRC(rc); 
    260     if (VBOX_FAILURE(rc)) 
    261         goto fail; 
    262  
    263     magic = be32_to_cpu(magic); 
    264     if (magic == VMDK3_MAGIC) 
    265     { 
    266         VMDK3Header header; 
    267         rc = RTFileRead(s->File, &header, sizeof(header), NULL); 
    268         AssertRC(rc); 
    269         if (VBOX_FAILURE(rc)) 
    270             goto fail; 
    271         s->cluster_sectors = le32_to_cpu(header.granularity); 
    272         s->l2_size = 1 << 9; 
    273         s->l1_size = 1 << 6; 
    274         s->total_sectors = le32_to_cpu(header.disk_sectors); 
    275         s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9; 
    276         s->l1_backup_table_offset = 0; 
    277         s->l1_entry_sectors = s->l2_size * s->cluster_sectors; 
    278  
    279         /* fill in the geometry structure */ 
    280         pDisk->Geometry.cCylinders = le32_to_cpu(header.cylinders); 
    281         pDisk->Geometry.cHeads = le32_to_cpu(header.heads); 
    282         pDisk->Geometry.cSectors = le32_to_cpu(header.sectors_per_track); 
    283         pDisk->Geometry.cbSector = VMDK_GEOMETRY_SECTOR_SIZE; 
    284     } 
    285     else if (magic == VMDK4_MAGIC) 
    286     { 
    287         VMDK4Header header; 
    288  
    289         rc = RTFileRead(s->File, &header, sizeof(header), NULL); 
    290         AssertRC(rc); 
    291         if (VBOX_FAILURE(rc)) 
    292             goto fail; 
    293         s->total_sectors = le64_to_cpu(header.capacity); 
    294         s->cluster_sectors = le64_to_cpu(header.granularity); 
    295         s->l2_size = le32_to_cpu(header.num_gtes_per_gte); 
    296         s->l1_entry_sectors = s->l2_size * s->cluster_sectors; 
    297         if (s->l1_entry_sectors <= 0) 
    298         { 
    299             rc = VERR_VDI_INVALID_HEADER; 
    300             goto fail; 
    301         } 
    302         s->l1_size = (s->total_sectors + s->l1_entry_sectors - 1) 
    303             / s->l1_entry_sectors; 
    304         s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9; 
    305         s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; 
    306  
    307         /* fill in the geometry structure */ 
    308         /// @todo we should read these properties from the DDB section 
    309         //  of the Disk DescriptorFile. So, the below values are just a 
    310         //  quick hack. 
    311         pDisk->Geometry.cCylinders = (le64_to_cpu(header.capacity) / 
    312                                       (16 * 63)); 
    313         pDisk->Geometry.cHeads = 16; 
    314         pDisk->Geometry.cSectors = 63; 
    315         pDisk->Geometry.cbSector = VMDK_GEOMETRY_SECTOR_SIZE; 
    316     } 
    317     else 
    318     { 
    319         rc = VERR_VDI_INVALID_HEADER; 
    320         goto fail; 
    321     } 
    322     /* read the L1 table */ 
    323     l1_size = s->l1_size * sizeof(uint32_t); 
    324     s->l1_table = (uint32_t *)RTMemAllocZ(l1_size); 
    325     if (!s->l1_table) 
    326     { 
    327         rc = VERR_NO_MEMORY; 
    328         goto fail; 
    329     } 
    330     rc = RTFileSeek(s->File, s->l1_table_offset, RTFILE_SEEK_BEGIN, NULL); 
    331     AssertRC(rc); 
    332     if (VBOX_FAILURE(rc)) 
    333         goto fail; 
    334     rc = RTFileRead(s->File, s->l1_table, l1_size, NULL); 
    335     AssertRC(rc); 
    336     if (VBOX_FAILURE(rc)) 
    337         goto fail; 
    338     for(i = 0; i < s->l1_size; i++) { 
    339         le32_to_cpus(&s->l1_table[i]); 
    340     } 
    341  
    342     if (s->l1_backup_table_offset) { 
    343         s->l1_backup_table = (uint32_t *)RTMemAllocZ(l1_size); 
    344         if (!s->l1_backup_table) 
    345         { 
    346             rc = VERR_NO_MEMORY; 
    347             goto fail; 
    348         } 
    349         rc = RTFileSeek(s->File, s->l1_backup_table_offset, RTFILE_SEEK_BEGIN, NULL); 
    350         AssertRC(rc); 
    351         if (VBOX_FAILURE(rc)) 
    352             goto fail; 
    353         rc = RTFileRead(s->File, s->l1_backup_table, l1_size, NULL); 
    354         AssertRC(rc); 
    355         if (VBOX_FAILURE(rc)) 
    356             goto fail; 
    357         for(i = 0; i < s->l1_size; i++) { 
    358             le32_to_cpus(&s->l1_backup_table[i]); 
    359         } 
    360     } 
    361  
    362     s->l2_cache = (uint32_t *)RTMemAllocZ(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t)); 
    363     if (!s->l2_cache) 
    364     { 
    365         rc = VERR_NO_MEMORY; 
    366         goto fail; 
    367     } 
    368  
    369     return VINF_SUCCESS; 
    370  
    371  fail: 
    372     Log(("vmdk_open failed with %Vrc\n", rc)); 
    373     if (s->l1_backup_table) 
    374         RTMemFree(s->l1_backup_table); 
    375     if (s->l1_table) 
    376         RTMemFree(s->l1_table); 
    377     if (s->l2_cache) 
    378         RTMemFree(s->l2_cache); 
    379     RTFileClose(s->File); 
    380     return rc; 
    381 
    382  
    383 static uint64_t get_cluster_offset(BDRVVmdkState *s, 
    384                                    uint64_t offset, int allocate) 
    385 
    386     unsigned int l1_index, l2_offset, l2_index; 
    387     int min_index, i, j; 
    388     uint32_t min_count, *l2_table, tmp; 
    389     uint64_t cluster_offset; 
    390     int rc; 
    391  
    392     l1_index = (offset >> 9) / s->l1_entry_sectors; 
    393     if (l1_index >= s->l1_size) 
    394         return 0; 
    395     l2_offset = s->l1_table[l1_index]; 
    396     if (!l2_offset) 
    397         return 0; 
    398     for(i = 0; i < L2_CACHE_SIZE; i++) { 
    399         if (l2_offset == s->l2_cache_offsets[i]) { 
    400             /* increment the hit count */ 
    401             if (++s->l2_cache_counts[i] == 0xffffffff) { 
    402                 for(j = 0; j < L2_CACHE_SIZE; j++) { 
    403                     s->l2_cache_counts[j] >>= 1; 
    404                 } 
    405             } 
    406             l2_table = s->l2_cache + (i * s->l2_size); 
    407             goto found; 
    408         } 
    409     } 
    410     /* not found: load a new entry in the least used one */ 
    411     min_index = 0; 
    412     min_count = 0xffffffff; 
    413     for(i = 0; i < L2_CACHE_SIZE; i++) { 
    414         if (s->l2_cache_counts[i] < min_count) { 
    415             min_count = s->l2_cache_counts[i]; 
    416             min_index = i; 
    417         } 
    418     } 
    419     l2_table = s->l2_cache + (min_index * s->l2_size); 
    420     rc = RTFileSeek(s->File, (int64_t)l2_offset * VMDK_GEOMETRY_SECTOR_SIZE, RTFILE_SEEK_BEGIN, NULL); 
    421     AssertRC(rc); 
    422     if (VBOX_FAILURE(rc)) 
    423         return 0; 
    424     rc = RTFileRead(s->File, l2_table, s->l2_size * sizeof(uint32_t), NULL); 
    425     AssertRC(rc); 
    426     if (VBOX_FAILURE(rc)) 
    427         return 0; 
    428     s->l2_cache_offsets[min_index] = l2_offset; 
    429     s->l2_cache_counts[min_index] = 1; 
    430  found: 
    431     l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size; 
    432     cluster_offset = le32_to_cpu(l2_table[l2_index]); 
    433     if (!cluster_offset) { 
    434         if (!allocate) 
    435             return 0; 
    436         rc = RTFileSeek(s->File, 0, RTFILE_SEEK_END, &cluster_offset); 
    437         AssertRC(rc); 
    438         if (VBOX_FAILURE(rc)) 
    439             return 0; 
    440         rc = RTFileSetSize(s->File, cluster_offset + (s->cluster_sectors << 9)); 
    441         AssertRC(rc); 
    442         if (VBOX_FAILURE(rc)) 
    443             return 0; 
    444         cluster_offset >>= 9; 
    445         /* update L2 table */ 
    446         tmp = cpu_to_le32(cluster_offset); 
    447         l2_table[l2_index] = tmp; 
    448         rc = RTFileSeek(s->File, ((int64_t)l2_offset * VMDK_GEOMETRY_SECTOR_SIZE) + (l2_index * sizeof(tmp)), RTFILE_SEEK_BEGIN, NULL); 
    449         AssertRC(rc); 
    450         if (VBOX_FAILURE(rc)) 
    451             return 0; 
    452         rc = RTFileWrite(s->File, &tmp, sizeof(tmp), NULL); 
    453         AssertRC(rc); 
    454         if (VBOX_FAILURE(rc)) 
    455             return 0; 
    456         /* update backup L2 table */ 
    457         if (s->l1_backup_table_offset != 0) { 
    458             l2_offset = s->l1_backup_table[l1_index]; 
    459  
    460             rc = RTFileSeek(s->File, ((int64_t)l2_offset * VMDK_GEOMETRY_SECTOR_SIZE) + (l2_index * sizeof(tmp)), RTFILE_SEEK_BEGIN, NULL); 
    461             AssertRC(rc); 
    462             if (VBOX_FAILURE(rc)) 
    463                 return 0; 
    464             rc = RTFileWrite(s->File, &tmp, sizeof(tmp), NULL); 
    465             AssertRC(rc); 
    466             if (VBOX_FAILURE(rc)) 
    467                 return 0; 
    468         } 
    469     } 
    470     cluster_offset <<= 9; 
    471     return cluster_offset; 
    472 
    473  
    474 #if 0 
    475 static int vmdk_is_allocated(BDRVVmdkState *s, int64_t sector_num, 
    476                              int nb_sectors, int *pnum) 
    477 
    478     int index_in_cluster, n; 
    479     uint64_t cluster_offset; 
    480  
    481     cluster_offset = get_cluster_offset(s, sector_num << 9, 0); 
    482     index_in_cluster = sector_num % s->cluster_sectors; 
    483     n = s->cluster_sectors - index_in_cluster; 
    484     if (n > nb_sectors) 
    485         n = nb_sectors; 
    486     *pnum = n; 
    487     return (cluster_offset != 0); 
    488 
    489 #endif 
    490  
    491 static int vmdk_read(BDRVVmdkState *s, int64_t sector_num, 
    492                     uint8_t *buf, int nb_sectors) 
    493 
    494     int index_in_cluster, n; 
    495     uint64_t cluster_offset; 
    496  
    497     while (nb_sectors > 0) { 
    498         cluster_offset = get_cluster_offset(s, sector_num << 9, 0); 
    499         index_in_cluster = sector_num % s->cluster_sectors; 
    500         n = s->cluster_sectors - index_in_cluster; 
    501         if (n > nb_sectors) 
    502             n = nb_sectors; 
    503         if (!cluster_offset) { 
    504             memset(buf, 0, VMDK_GEOMETRY_SECTOR_SIZE * n); 
    505         } else { 
    506             int rc = RTFileSeek(s->File, cluster_offset + index_in_cluster * VMDK_GEOMETRY_SECTOR_SIZE, RTFILE_SEEK_BEGIN, NULL); 
    507             AssertRC(rc); 
    508             if (VBOX_FAILURE(rc)) 
    509                 return rc; 
    510  
    511             rc = RTFileRead(s->File, buf, n * VMDK_GEOMETRY_SECTOR_SIZE, NULL); 
    512             AssertRC(rc); 
    513             if (VBOX_FAILURE(rc)) 
    514                 return rc; 
    515         } 
    516         nb_sectors -= n; 
    517         sector_num += n; 
    518         buf += n * VMDK_GEOMETRY_SECTOR_SIZE; 
    519     } 
    520     return VINF_SUCCESS; 
    521 
    522  
    523 static int vmdk_write(BDRVVmdkState *s, int64_t sector_num, 
    524                      const uint8_t *buf, int nb_sectors) 
    525 
    526     int index_in_cluster, n; 
    527     uint64_t cluster_offset; 
    528  
    529     while (nb_sectors > 0) { 
    530         index_in_cluster = sector_num & (s->cluster_sectors - 1); 
    531         n = s->cluster_sectors - index_in_cluster; 
    532         if (n > nb_sectors) 
    533             n = nb_sectors; 
    534         cluster_offset = get_cluster_offset(s, sector_num << 9, 1); 
    535         if (!cluster_offset) 
    536             return VERR_IO_SECTOR_NOT_FOUND; 
    537  
    538         int rc = RTFileSeek(s->File, cluster_offset + index_in_cluster * VMDK_GEOMETRY_SECTOR_SIZE, RTFILE_SEEK_BEGIN, NULL); 
    539         AssertRC(rc); 
    540         if (VBOX_FAILURE(rc)) 
    541             return rc; 
    542  
    543         rc = RTFileWrite(s->File, buf, n * VMDK_GEOMETRY_SECTOR_SIZE, NULL); 
    544         AssertRC(rc); 
    545         if (VBOX_FAILURE(rc)) 
    546             return rc; 
    547  
    548         nb_sectors -= n; 
    549         sector_num += n; 
    550         buf += n * VMDK_GEOMETRY_SECTOR_SIZE; 
    551     } 
    552     return VINF_SUCCESS; 
    553 
    554  
    555 static void vmdk_close(BDRVVmdkState *s) 
    556 
    557     RTMemFree(s->l1_table); 
    558     RTMemFree(s->l2_cache); 
    559     RTFileClose(s->File); 
    560 
    561  
    562 static void vmdk_flush(BDRVVmdkState *s) 
    563 
    564     RTFileFlush(s->File); 
    565 
    566  
    567  
    568 /** 
    569  * Get read/write mode of VMDK HDD. 
    570  * 
    571  * @returns Disk ReadOnly status. 
    572  * @returns true if no one VMDK image is opened in HDD container. 
    573  */ 
    574 IDER3DECL(bool) VMDKDiskIsReadOnly(PVMDKDISK pDisk) 
    575 
    576     /* sanity check */ 
    577     Assert(pDisk); 
    578     AssertMsg(pDisk->u32Signature == VMDKDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 
    579  
    580     LogFlow(("VmdkDiskIsReadOnly: returns %u\n", pDisk->VmdkState.fReadOnly)); 
    581     return pDisk->VmdkState.fReadOnly; 
    582 
    583  
    584  
    585 /** 
    586  * Get disk size of VMDK HDD container. 
    587  * 
    588  * @returns Virtual disk size in bytes. 
    589  * @returns 0 if no one VMDK image is opened in HDD container. 
    590  */ 
    591 IDER3DECL(uint64_t) VMDKDiskGetSize(PVMDKDISK pDisk) 
    592 
    593     /* sanity check */ 
    594     Assert(pDisk); 
    595     AssertMsg(pDisk->u32Signature == VMDKDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 
    596  
    597     return pDisk->VmdkState.total_sectors * VMDK_GEOMETRY_SECTOR_SIZE; 
    598 
    599  
    600 /** 
    601  * Get block size of VMDK HDD container. 
    602  * 
    603  * @returns VDI image block size in bytes. 
    604  * @returns 0 if no one VMDK image is opened in HDD container. 
    605  */ 
    606 IDER3DECL(unsigned) VMDKDiskGetBlockSize(PVMDKDISK pDisk) 
    607 
    608     /* sanity check */ 
    609     Assert(pDisk); 
    610     AssertMsg(pDisk->u32Signature == VMDKDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 
    611  
    612     return VMDK_GEOMETRY_SECTOR_SIZE; 
    613 
    614  
    615 /** 
    616  * Get virtual disk geometry stored in image file. 
    617  * 
    618  * @returns VBox status code. 
    619  * @param   pDisk           Pointer to VMDK HDD container. 
    620  * @param   pcCylinders     Where to store the number of cylinders. NULL is ok. 
    621  * @param   pcHeads         Where to store the number of heads. NULL is ok. 
    622  * @param   pcSectors       Where to store the number of sectors. NULL is ok. 
    623  */ 
    624 IDER3DECL(int) VMDKDiskGetGeometry(PVMDKDISK pDisk, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors) 
    625 
    626     /* sanity check */ 
    627     Assert(pDisk); 
    628     AssertMsg(pDisk->u32Signature == VMDKDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 
    629  
    630     PVMDKDISKGEOMETRY pGeometry = &pDisk->Geometry; 
    631  
    632     LogFlow(("VDIDiskGetGeometry: C/H/S = %u/%u/%u\n", 
    633              pGeometry->cCylinders, pGeometry->cHeads, pGeometry->cSectors)); 
    634  
    635     int rc = VINF_SUCCESS; 
    636  
    637     if (    pGeometry->cCylinders > 0 
    638         &&  pGeometry->cHeads > 0 
    639         &&  pGeometry->cSectors > 0) 
    640     { 
    641         if (pcCylinders) 
    642             *pcCylinders = pDisk->Geometry.cCylinders; 
    643         if (pcHeads) 
    644             *pcHeads = pDisk->Geometry.cHeads; 
    645         if (pcSectors) 
    646             *pcSectors = pDisk->Geometry.cSectors; 
    647     } 
    648     else 
    649         rc = VERR_VDI_GEOMETRY_NOT_SET; 
    650  
    651     LogFlow(("VDIDiskGetGeometry: returns %Vrc\n", rc)); 
    652     return rc; 
    653 
    654  
    655 /** 
    656  * Store virtual disk geometry into base image file of HDD container. 
    657  * 
    658  * Note that in case of unrecoverable error all images of HDD container will be closed. 
    659  * 
    660  * @returns VBox status code. 
    661  * @param   pDisk           Pointer to VMDK HDD container. 
    662  * @param   cCylinders      Number of cylinders. 
    663  * @param   cHeads          Number of heads. 
    664  * @param   cSectors        Number of sectors. 
    665  */ 
    666 IDER3DECL(int) VMDKDiskSetGeometry(PVMDKDISK pDisk, unsigned cCylinders, unsigned cHeads, unsigned cSectors) 
    667 
    668     LogFlow(("VMDKDiskSetGeometry: C/H/S = %u/%u/%u\n", cCylinders, cHeads, cSectors)); 
    669     /* sanity check */ 
    670     Assert(pDisk); 
    671     AssertMsg(pDisk->u32Signature == VMDKDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 
    672  
    673     pDisk->Geometry.cCylinders = cCylinders; 
    674     pDisk->Geometry.cHeads     = cHeads; 
    675     pDisk->Geometry.cSectors   = cSectors; 
    676     pDisk->Geometry.cbSector   = VMDK_GEOMETRY_SECTOR_SIZE; 
    677  
    678     /** @todo Update header information in base image file. */ 
    679     return VINF_SUCCESS; 
    680 
    681  
    682 /** 
    683  * Get number of opened images in HDD container. 
    684  * 
    685  * @returns Number of opened images for HDD container. 0 if no images is opened. 
    686  * @param   pDisk           Pointer to VMDK HDD container. 
    687  */ 
    688 IDER3DECL(int) VMDKDiskGetImagesCount(PVMDKDISK pDisk) 
    689 
    690     /* sanity check */ 
    691     Assert(pDisk); 
    692     AssertMsg(pDisk->u32Signature == VMDKDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 
    693  
    694     return 1; 
    695 
     163        Log(("%s: geometry not available.\n", __FUNCTION__)); 
     164        rc = VERR_PDM_GEOMETRY_NOT_SET; 
     165    } 
     166    LogFlow(("%s: returns %Vrc (CHS=%d/%d/%d)\n", __FUNCTION__, 
     167             rc, *pcCylinders, *pcHeads, *pcSectors)); 
     168    return rc; 
     169
     170 
     171/** @copydoc PDMIMEDIA::pfnBiosSetGeometry */ 
     172static DECLCALLBACK(int) vdBiosSetGeometry(PPDMIMEDIA pInterface, 
     173                                           uint32_t cCylinders, 
     174                                           uint32_t cHeads, 
     175                                           uint32_t cSectors) 
     176
     177    LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__, 
     178             cCylinders, cHeads, cSectors)); 
     179    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     180    int rc = VDSetGeometry(pData->pDisk, cCylinders, cHeads, cSectors); 
     181    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc)); 
     182    return rc; 
     183
     184 
     185/** @copydoc PDMIMEDIA::pfnBiosGetTranslation */ 
     186static DECLCALLBACK(int) vdBiosGetTranslation(PPDMIMEDIA pInterface, 
     187                                              PPDMBIOSTRANSLATION penmTranslation) 
     188
     189    LogFlow(("%s:\n", __FUNCTION__)); 
     190    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface); 
     191    int rc = VDGetTranslation(pData->pDisk, penmTranslation); 
     192    LogFlow(("%s: returns %Vrc (%d)\n", __FUNCTION__, rc, *penmTranslation)); 
     193    return rc; 
     194
     195 
     196/** @copydoc PDMIMEDIA::pfnBiosSetTranslation */ 
     197static DECLCALLBACK(int) vdBiosSetTranslation(PPDMIMEDIA pInterface, 
     198                                              PDMBIOSTRANSLATION enmT