VirtualBox

Changeset 6291 in vbox


Ignore:
Timestamp:
Jan 9, 2008 10:57:05 AM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
27155
Message:

Big virtual disk changeset containing several modifications

  • remove the always buggy translation setting and replace it with two sets of geometries, physical and logical
  • complete vmdk creation (fixed/dynamic variants, both split in 2G chunks and single file)
  • implemented VBoxHDD-new generic snapshot support, i.e. diff image creation and image merging (completely untested, I'm pretty sure there are bugs)
  • assorted changes which generalize the VBoxHDD-new interfaces (both externally and internally)
Location:
trunk
Files:
2 deleted
25 edited

Legend:

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

    r5999 r6291  
    55
    66/*
    7  * Copyright (C) 2006-2007 innotek GmbH
     7 * Copyright (C) 2006-2008 innotek GmbH
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    5656/** Get VDI minor version from combined version. */
    5757#define VDI_GET_VERSION_MINOR(uVer)    ((uVer) & 0xffff)
     58
     59/** Placeholder for specifying the last opened image. */
     60#define VD_LAST_IMAGE               0xffffffffU
    5861
    5962/** @name VBox HDD container image types
     
    97100/** Mask of valid image flags for VDI. */
    98101#define VD_VDI_IMAGE_FLAGS_MASK             (VD_IMAGE_FLAGS_NONE | VD_VDI_IMAGE_FLAGS_ZERO_EXPAND)
     102
     103/** Mask of all valid image flags for all formats. */
     104#define VD_IMAGE_FLAGS_MASK                 (VD_VMDK_IMAGE_FLAGS_MASK | VD_VDI_IMAGE_FLAGS_MASK)
    99105
    100106/** Default image flags. */
     
    132138typedef struct VBOXHDDRAW
    133139{
     140    /** Signature for structure. Must be 'R', 'A', 'W', '\0'. Actually a trick
     141     * to make logging of the comment string produce sensible results. */
     142    char            szSignature[4];
    134143    /** Flag whether access to full disk should be given (ignoring the
    135144     * partition information below). */
     
    189198
    190199/**
    191  * Allocates and initializes an empty VBox HDD container.
     200 * Allocates and initializes an empty HDD container.
    192201 * No image files are opened.
    193202 *
     
    196205 * @param   pfnError        Callback for setting extended error information.
    197206 * @param   pvErrorUser     Opaque parameter for pfnError.
    198  * @param   ppDisk          Where to store the reference to the VBox HDD container.
    199  */
    200 VBOXDDU_DECL(int) VDCreate(const char *pszBackend, PFNVDERROR pfnError, void *pvErrorUser, PVBOXHDD *ppDisk);
    201 
    202 /**
    203  * Destroys the VBox HDD container.
     207 * @param   ppDisk          Where to store the reference to HDD container.
     208 */
     209VBOXDDU_DECL(int) VDCreate(const char *pszBackend, PFNVDERROR pfnError,
     210                           void *pvErrorUser, PVBOXHDD *ppDisk);
     211
     212/**
     213 * Destroys HDD container.
    204214 * If container has opened image files they will be closed.
    205215 *
    206  * @param   pDisk           Pointer to VBox HDD container.
     216 * @param   pDisk           Pointer to HDD container.
    207217 */
    208218VBOXDDU_DECL(void) VDDestroy(PVBOXHDD pDisk);
    209219
    210220/**
    211  * Try to get the backend name which can use this image. 
     221 * Try to get the backend name which can use this image.
    212222 *
    213223 * @returns VBox status code.
     
    221231 * Opens an image file.
    222232 *
    223  * The first opened image file in a HDD container must have a base image type,
     233 * The first opened image file in HDD container must have a base image type,
    224234 * others (next opened images) must be differencing or undo images.
    225235 * Linkage is checked for differencing image to be consistent with the previously opened image.
     
    232242 *
    233243 * @returns VBox status code.
    234  * @param   pDisk           Pointer to VBox HDD container.
     244 * @param   pDisk           Pointer to HDD container.
    235245 * @param   pszFilename     Name of the image file to open.
    236246 * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
    237247 */
    238 VBOXDDU_DECL(int) VDOpen(PVBOXHDD pDisk, const char *pszFilename, unsigned uOpenFlags);
     248VBOXDDU_DECL(int) VDOpen(PVBOXHDD pDisk, const char *pszFilename,
     249                         unsigned uOpenFlags);
    239250
    240251/**
     
    242253 *
    243254 * @returns VBox status code.
    244  * @param   pDisk           Pointer to VBox HDD container.
     255 * @param   pDisk           Pointer to HDD container.
    245256 * @param   pszFilename     Name of the image file to create.
    246257 * @param   enmType         Image type, only base image types are acceptable.
     
    248259 * @param   uImageFlags     Flags specifying special image features.
    249260 * @param   pszComment      Pointer to image comment. NULL is ok.
    250  * @param   cCylinders      Number of cylinders (must be <= 16383).
    251  * @param   cHeads          Number of heads (must be <= 16).
    252  * @param   cSectors        Number of sectors (must be <= 63);
     261 * @param   pPCHSGeometry   Pointer to physical disk geometry <= (16383,16,63). Not NULL.
     262 * @param   pLCHSGeometry   Pointer to logical disk geometry <= (1024,255,63). Not NULL.
    253263 * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
    254264 * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
     
    258268                               VDIMAGETYPE enmType, uint64_t cbSize,
    259269                               unsigned uImageFlags, const char *pszComment,
    260                                unsigned cCylinders, unsigned cHeads,
    261                                unsigned cSectors, unsigned uOpenFlags,
    262                                PFNVMPROGRESS pfnProgress, void *pvUser);
     270                               PCPDMMEDIAGEOMETRY pPCHSGeometry,
     271                               PCPDMMEDIAGEOMETRY pLCHSGeometry,
     272                               unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
     273                               void *pvUser);
    263274
    264275/**
     
    267278 *
    268279 * @returns VBox status code.
    269  * @param   pDisk           Pointer to VBox HDD container.
     280 * @param   pDisk           Pointer to HDD container.
    270281 * @param   pszFilename     Name of the differencing image file to create.
    271282 * @param   uImageFlags     Flags specifying special image features.
     
    277288VBOXDDU_DECL(int) VDCreateDiff(PVBOXHDD pDisk, const char *pszFilename,
    278289                               unsigned uImageFlags, const char *pszComment,
    279                                unsigned uOpenFlags,
    280                                PFNVMPROGRESS pfnProgress, void *pvUser);
    281 
    282 /**
    283  * Merges two images having a parent/child relationship (both directions).
    284  * As a side effect the source image is deleted from both the disk and
    285  * the images in the VBox HDD container.
    286  *
    287  * @returns VBox status code.
    288  * @param   pDisk           Pointer to VBox HDD container.
     290                               unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
     291                               void *pvUser);
     292
     293/**
     294 * Merges two images (not necessarily with direct parent/child relationship).
     295 * As a side effect the source image and potentially the other images which
     296 * are also merged to the destination are deleted from both the disk and the
     297 * images in the HDD container.
     298 *
     299 * @returns VBox status code.
     300 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     301 * @param   pDisk           Pointer to HDD container.
    289302 * @param   nImageFrom      Name of the image file to merge from.
    290303 * @param   nImageTo        Name of the image file to merge to.
     
    292305 * @param   pvUser          User argument for the progress callback.
    293306 */
    294 VBOXDDU_DECL(int) VDMerge(PVBOXHDD pDisk, unsigned nImageFrom, unsigned nImageTo,
    295                           PFNVMPROGRESS pfnProgress, void *pvUser);
    296 
    297 /**
    298  * Copies an image from one VBox HDD container to another.
    299  * The copy is opened in the target VBox HDD container.
     307VBOXDDU_DECL(int) VDMerge(PVBOXHDD pDisk, unsigned nImageFrom,
     308                          unsigned nImageTo, PFNVMPROGRESS pfnProgress,
     309                          void *pvUser);
     310
     311/**
     312 * Copies an image from one HDD container to another.
     313 * The copy is opened in the target HDD container.
    300314 * It is possible to convert between different image formats, because the
    301  * backend for the destination VBox HDD container may be different from the
     315 * backend for the destination HDD container may be different from the
    302316 * source container.
    303  * If both the source and destination reference the same VBox HDD container,
    304  * then the image is moved (by copying/deleting) to the new location.
     317 * If both the source and destination reference the same HDD container,
     318 * then the image is moved (by copying/deleting or renaming) to the new location.
    305319 * The source container is unchanged if the move operation fails, otherwise
    306320 * the image at the new location is opened in the same way as the old one was.
    307321 *
    308322 * @returns VBox status code.
    309  * @param   pDiskFrom       Pointer to source VBox HDD container.
    310  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    311  * @param   pDiskTo         Pointer to destination VBox HDD container.
     323 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     324 * @param   pDiskFrom       Pointer to source HDD container.
     325 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     326 * @param   pDiskTo         Pointer to destination HDD container.
     327 * @param   pszFilename     New name of the image (may be NULL if pDiskFrom == pDiskTo).
     328 * @param   fMoveByRename   If true, attempt to perform a move by renaming (if successful the new size is ignored).
     329 * @param   cbSize          New image size (0 means leave unchanged).
    312330 * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
    313331 * @param   pvUser          User argument for the progress callback.
    314332 */
    315333VBOXDDU_DECL(int) VDCopy(PVBOXHDD pDiskFrom, unsigned nImage, PVBOXHDD pDiskTo,
    316                          PFNVMPROGRESS pfnProgress, void *pvUser);
    317 
    318 /**
    319  * Compacts a growing image file by removing zeroed data blocks.
    320  * Optionally defragments data in the image so that ascending sector numbers
    321  * are stored in ascending location in the image file.
    322  *
    323  * @todo maybe include this function in VDCopy.
    324  *
    325  * @returns VBox status code.
    326  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    327  * @param   pDisk           Pointer to VBox HDD container.
    328  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    329  * @param   fDefragment     If true, reorder file data so that sectors are stored in ascending order.
    330  * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
    331  * @param   pvUser          User argument for the progress callback.
    332  */
    333 VBOXDDU_DECL(int) VDCompact(PVBOXHDD pDisk, unsigned nImage,
    334                             bool fDefragment,
    335                             PFNVMPROGRESS pfnProgress, void *pvUser);
    336 
    337 /**
    338  * Resizes an image. Allows setting the disk size to both larger and smaller
    339  * values than the current disk size.
    340  *
    341  * @returns VBox status code.
    342  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    343  * @param   pDisk           Pointer to VBox HDD container.
    344  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    345  * @param   cbSize          New image size in bytes.
    346  * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
    347  * @param   pvUser          User argument for the progress callback.
    348  */
    349 VBOXDDU_DECL(int) VDResize(PVBOXHDD pDisk, unsigned nImage, uint64_t cbSize,
    350                            PFNVMPROGRESS pfnProgress, void *pvUser);
    351 
    352 /**
    353  * Closes the last opened image file in the HDD container. Leaves all changes inside it.
     334                         const char *pszFilename, bool fMoveByRename,
     335                         uint64_t cbSize, PFNVMPROGRESS pfnProgress,
     336                         void *pvUser);
     337
     338/**
     339 * Closes the last opened image file in HDD container.
    354340 * If previous image file was opened in read-only mode (that is normal) and closing image
    355341 * was opened in read-write mode (the whole disk was in read-write mode) - the previous image
    356342 * will be reopened in read/write mode.
    357343 *
    358  * @param   pDisk           Pointer to VBox HDD container.
     344 * @returns VBox status code.
     345 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     346 * @param   pDisk           Pointer to HDD container.
    359347 * @param   fDelete         If true, delete the image from the host disk.
    360348 */
     
    364352 * Closes all opened image files in HDD container.
    365353 *
    366  * @param   pDisk           Pointer to VBox HDD container.
     354 * @returns VBox status code.
     355 * @param   pDisk           Pointer to HDD container.
    367356 */
    368357VBOXDDU_DECL(int) VDCloseAll(PVBOXHDD pDisk);
     
    373362 * @returns VBox status code.
    374363 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    375  * @param   pDisk           Pointer to VBox HDD container.
     364 * @param   pDisk           Pointer to HDD container.
    376365 * @param   uOffset         Offset of first reading byte from start of disk.
    377366 * @param   pvBuf           Pointer to buffer for reading data.
     
    385374 * @returns VBox status code.
    386375 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    387  * @param   pDisk           Pointer to VBox HDD container.
     376 * @param   pDisk           Pointer to HDD container.
    388377 * @param   uOffset         Offset of first writing byte from start of disk.
    389378 * @param   pvBuf           Pointer to buffer for writing data.
     
    397386 * @returns VBox status code.
    398387 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    399  * @param   pDisk           Pointer to VBox HDD container.
     388 * @param   pDisk           Pointer to HDD container.
    400389 */
    401390VBOXDDU_DECL(int) VDFlush(PVBOXHDD pDisk);
     
    405394 *
    406395 * @returns Number of opened images for HDD container. 0 if no images have been opened.
    407  * @param   pDisk           Pointer to VBox HDD container.
     396 * @param   pDisk           Pointer to HDD container.
    408397 */
    409398VBOXDDU_DECL(unsigned) VDGetCount(PVBOXHDD pDisk);
    410399
    411400/**
    412  * Get read/write mode of the VBox HDD container.
     401 * Get read/write mode of HDD container.
    413402 *
    414403 * @returns Virtual disk ReadOnly status.
    415404 * @returns true if no image is opened in HDD container.
    416  * @param   pDisk           Pointer to VBox HDD container.
     405 * @param   pDisk           Pointer to HDD container.
    417406 */
    418407VBOXDDU_DECL(bool) VDIsReadOnly(PVBOXHDD pDisk);
    419408
    420409/**
    421  * Get total disk size of the VBox HDD container.
     410 * Get total capacity of an image in HDD container.
    422411 *
    423412 * @returns Virtual disk size in bytes.
    424  * @returns 0 if no image is opened in HDD container.
    425  * @param   pDisk           Pointer to VBox HDD container.
    426  */
    427 VBOXDDU_DECL(uint64_t) VDGetSize(PVBOXHDD pDisk);
    428 
    429 /**
    430  * Get virtual disk geometry stored in HDD container.
    431  *
    432  * @returns VBox status code.
    433  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     413 * @returns 0 if image with specified number was not opened.
     414 * @param   pDisk           Pointer to HDD container.
     415 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     416 */
     417VBOXDDU_DECL(uint64_t) VDGetSize(PVBOXHDD pDisk, unsigned nImage);
     418
     419/**
     420 * Get total file size of an image in HDD container.
     421 *
     422 * @returns Virtual disk size in bytes.
     423 * @returns 0 if image with specified number was not opened.
     424 * @param   pDisk           Pointer to HDD container.
     425 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     426 */
     427VBOXDDU_DECL(uint64_t) VDGetFileSize(PVBOXHDD pDisk, unsigned nImage);
     428
     429/**
     430 * Get virtual disk PCHS geometry of an image in HDD container.
     431 *
     432 * @returns VBox status code.
     433 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    434434 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
    435  * @param   pDisk           Pointer to VBox HDD container.
    436  * @param   pcCylinders     Where to store the number of cylinders. NULL is ok.
    437  * @param   pcHeads         Where to store the number of heads. NULL is ok.
    438  * @param   pcSectors       Where to store the number of sectors. NULL is ok.
    439  */
    440 VBOXDDU_DECL(int) VDGetGeometry(PVBOXHDD pDisk,
    441                                 unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors);
    442 
    443 /**
    444  * Store virtual disk geometry in HDD container.
    445  *
    446  * Note that in case of unrecoverable error all images in HDD container will be closed.
    447  *
    448  * @returns VBox status code.
    449  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    450  * @param   pDisk           Pointer to VBox HDD container.
    451  * @param   cCylinders      Number of cylinders.
    452  * @param   cHeads          Number of heads.
    453  * @param   cSectors        Number of sectors.
    454  */
    455 VBOXDDU_DECL(int) VDSetGeometry(PVBOXHDD pDisk,
    456                                 unsigned cCylinders, unsigned cHeads, unsigned cSectors);
    457 
    458 /**
    459  * Get virtual disk translation mode stored in HDD container.
    460  *
    461  * @returns VBox status code.
    462  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     435 * @param   pDisk           Pointer to HDD container.
     436 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     437 * @param   pPCHSGeometry   Where to store PCHS geometry. Not NULL.
     438 */
     439VBOXDDU_DECL(int) VDGetPCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     440                                    PPDMMEDIAGEOMETRY pPCHSGeometry);
     441
     442/**
     443 * Store virtual disk PCHS geometry of an image in HDD container.
     444 *
     445 * @returns VBox status code.
     446 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     447 * @param   pDisk           Pointer to HDD container.
     448 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     449 * @param   pPCHSGeometry   Where to load PCHS geometry from. Not NULL.
     450 */
     451VBOXDDU_DECL(int) VDSetPCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     452                                    PCPDMMEDIAGEOMETRY pPCHSGeometry);
     453
     454/**
     455 * Get virtual disk LCHS geometry of an image in HDD container.
     456 *
     457 * @returns VBox status code.
     458 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    463459 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
    464  * @param   pDisk           Pointer to VBox HDD container.
    465  * @param   penmTranslation Where to store the translation mode (see pdm.h).
    466  */
    467 VBOXDDU_DECL(int) VDGetTranslation(PVBOXHDD pDisk, PPDMBIOSTRANSLATION penmTranslation);
    468 
    469 /**
    470  * Store virtual disk translation mode in HDD container.
    471  *
    472  * Note that in case of unrecoverable error all images in HDD container will be closed.
    473  *
    474  * @returns VBox status code.
    475  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    476  * @param   pDisk           Pointer to VBox HDD container.
    477  * @param   enmTranslation  Translation mode (see pdm.h).
    478  */
    479 VBOXDDU_DECL(int) VDSetTranslation(PVBOXHDD pDisk, PDMBIOSTRANSLATION enmTranslation);
     460 * @param   pDisk           Pointer to HDD container.
     461 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     462 * @param   pLCHSGeometry   Where to store LCHS geometry. Not NULL.
     463 */
     464VBOXDDU_DECL(int) VDGetLCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     465                                    PPDMMEDIAGEOMETRY pLCHSGeometry);
     466
     467/**
     468 * Store virtual disk LCHS geometry of an image in HDD container.
     469 *
     470 * @returns VBox status code.
     471 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     472 * @param   pDisk           Pointer to HDD container.
     473 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     474 * @param   pLCHSGeometry   Where to load LCHS geometry from. Not NULL.
     475 */
     476VBOXDDU_DECL(int) VDSetLCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     477                                    PCPDMMEDIAGEOMETRY pLCHSGeometry);
    480478
    481479/**
     
    484482 * @returns VBox status code.
    485483 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    486  * @param   pDisk           Pointer to VBox HDD container.
     484 * @param   pDisk           Pointer to HDD container.
    487485 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    488486 * @param   puVersion       Where to store the image version.
    489487 */
    490 VBOXDDU_DECL(int) VDGetVersion(PVBOXHDD pDisk, unsigned nImage, unsigned *puVersion);
     488VBOXDDU_DECL(int) VDGetVersion(PVBOXHDD pDisk, unsigned nImage,
     489                               unsigned *puVersion);
    491490
    492491/**
     
    495494 * @returns VBox status code.
    496495 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    497  * @param   pDisk           Pointer to VBox HDD container.
     496 * @param   pDisk           Pointer to HDD container.
    498497 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    499498 * @param   penmType        Where to store the image type.
    500499 */
    501 VBOXDDU_DECL(int) VDGetImageType(PVBOXHDD pDisk, unsigned nImage, PVDIMAGETYPE penmType);
     500VBOXDDU_DECL(int) VDGetImageType(PVBOXHDD pDisk, unsigned nImage,
     501                                 PVDIMAGETYPE penmType);
    502502
    503503/**
     
    506506 * @returns VBox status code.
    507507 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    508  * @param   pDisk           Pointer to VBox HDD container.
     508 * @param   pDisk           Pointer to HDD container.
    509509 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    510510 * @param   puImageFlags    Where to store the image flags.
     
    513513
    514514/**
    515  * Get open flags of last opened image in HDD container.
    516  *
    517  * @returns VBox status code.
    518  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    519  * @param   pDisk           Pointer to VBox HDD container.
     515 * Get open flags of image in HDD container.
     516 *
     517 * @returns VBox status code.
     518 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     519 * @param   pDisk           Pointer to HDD container.
     520 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    520521 * @param   puOpenFlags     Where to store the image open flags.
    521522 */
    522 VBOXDDU_DECL(int) VDGetOpenFlags(PVBOXHDD pDisk, unsigned *puOpenFlags);
    523 
    524 /**
    525  * Set open flags of last opened image in HDD container.
     523VBOXDDU_DECL(int) VDGetOpenFlags(PVBOXHDD pDisk, unsigned nImage,
     524                                 unsigned *puOpenFlags);
     525
     526/**
     527 * Set open flags of image in HDD container.
    526528 * This operation may cause file locking changes and/or files being reopened.
    527529 * Note that in case of unrecoverable error all images in HDD container will be closed.
     
    529531 * @returns VBox status code.
    530532 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    531  * @param   pDisk           Pointer to VBox HDD container.
     533 * @param   pDisk           Pointer to HDD container.
     534 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    532535 * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
    533536 */
    534 VBOXDDU_DECL(int) VDSetOpenFlags(PVBOXHDD pDisk, unsigned uOpenFlags);
     537VBOXDDU_DECL(int) VDSetOpenFlags(PVBOXHDD pDisk, unsigned nImage,
     538                                 unsigned uOpenFlags);
    535539
    536540/**
    537541 * Get base filename of image in HDD container. Some image formats use
    538  * other filenames as well, so don't use this for anything but for informational
     542 * other filenames as well, so don't use this for anything but informational
    539543 * purposes.
    540544 *
     
    542546 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    543547 * @returns VERR_BUFFER_OVERFLOW if pszFilename buffer too small to hold filename.
    544  * @param   pDisk           Pointer to VBox HDD container.
     548 * @param   pDisk           Pointer to HDD container.
    545549 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    546550 * @param   pszFilename     Where to store the image file name.
    547551 * @param   cbFilename      Size of buffer pszFilename points to.
    548552 */
    549 VBOXDDU_DECL(int) VDGetFilename(PVBOXHDD pDisk, unsigned nImage, char *pszFilename, unsigned cbFilename);
     553VBOXDDU_DECL(int) VDGetFilename(PVBOXHDD pDisk, unsigned nImage,
     554                                char *pszFilename, unsigned cbFilename);
    550555
    551556/**
     
    555560 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    556561 * @returns VERR_BUFFER_OVERFLOW if pszComment buffer too small to hold comment text.
    557  * @param   pDisk           Pointer to VBox HDD container.
     562 * @param   pDisk           Pointer to HDD container.
    558563 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    559564 * @param   pszComment      Where to store the comment string of image. NULL is ok.
    560565 * @param   cbComment       The size of pszComment buffer. 0 is ok.
    561566 */
    562 VBOXDDU_DECL(int) VDGetComment(PVBOXHDD pDisk, unsigned nImage, char *pszComment, unsigned cbComment);
     567VBOXDDU_DECL(int) VDGetComment(PVBOXHDD pDisk, unsigned nImage,
     568                               char *pszComment, unsigned cbComment);
    563569
    564570/**
     
    567573 * @returns VBox status code.
    568574 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    569  * @param   pDisk           Pointer to VBox HDD container.
     575 * @param   pDisk           Pointer to HDD container.
    570576 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    571577 * @param   pszComment      New comment string (UTF-8). NULL is allowed to reset the comment.
    572578 */
    573 VBOXDDU_DECL(int) VDSetComment(PVBOXHDD pDisk, unsigned nImage, const char *pszComment);
     579VBOXDDU_DECL(int) VDSetComment(PVBOXHDD pDisk, unsigned nImage,
     580                               const char *pszComment);
    574581
    575582/**
     
    578585 * @returns VBox status code.
    579586 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    580  * @param   pDisk           Pointer to VBox HDD container.
     587 * @param   pDisk           Pointer to HDD container.
    581588 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    582589 * @param   pUuid           Where to store the image UUID.
     
    589596 * @returns VBox status code.
    590597 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    591  * @param   pDisk           Pointer to VBox HDD container.
    592  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    593  * @param   pUuid           Optional parameter, new UUID of the image.
     598 * @param   pDisk           Pointer to HDD container.
     599 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     600 * @param   pUuid           New UUID of the image. If NULL, a new UUID is created.
    594601 */
    595602VBOXDDU_DECL(int) VDSetUuid(PVBOXHDD pDisk, unsigned nImage, PCRTUUID pUuid);
     
    600607 * @returns VBox status code.
    601608 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    602  * @param   pDisk           Pointer to VBox HDD container.
     609 * @param   pDisk           Pointer to HDD container.
    603610 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    604611 * @param   pUuid           Where to store the image modification UUID.
    605612 */
    606 VBOXDDU_DECL(int) VDGetModificationUuid(PVBOXHDD pDisk, unsigned nImage, PRTUUID pUuid);
     613VBOXDDU_DECL(int) VDGetModificationUuid(PVBOXHDD pDisk, unsigned nImage,
     614                                        PRTUUID pUuid);
    607615
    608616/**
     
    611619 * @returns VBox status code.
    612620 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    613  * @param   pDisk           Pointer to VBox HDD container.
    614  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    615  * @param   pUuid           Optional parameter, new last modification UUID of the image.
    616  */
    617 VBOXDDU_DECL(int) VDSetModificationUuid(PVBOXHDD pDisk, unsigned nImage, PCRTUUID pUuid);
     621 * @param   pDisk           Pointer to HDD container.
     622 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     623 * @param   pUuid           New modification UUID of the image. If NULL, a new UUID is created.
     624 */
     625VBOXDDU_DECL(int) VDSetModificationUuid(PVBOXHDD pDisk, unsigned nImage,
     626                                        PCRTUUID pUuid);
    618627
    619628/**
     
    622631 * @returns VBox status code.
    623632 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    624  * @param   pDisk           Pointer to VBox HDD container.
     633 * @param   pDisk           Pointer to HDD container.
    625634 * @param   nImage          Image number, counts from 0. 0 is always base image of the container.
    626635 * @param   pUuid           Where to store the parent image UUID.
    627636 */
    628 VBOXDDU_DECL(int) VDGetParentUuid(PVBOXHDD pDisk, unsigned nImage, PRTUUID pUuid);
     637VBOXDDU_DECL(int) VDGetParentUuid(PVBOXHDD pDisk, unsigned nImage,
     638                                  PRTUUID pUuid);
    629639
    630640/**
     
    632642 *
    633643 * @returns VBox status code.
    634  * @param   pDisk           Pointer to VBox HDD container.
    635  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    636  * @param   pUuid           Optional parameter, new parent UUID of the image.
    637  */
    638 VBOXDDU_DECL(int) VDSetParentUuid(PVBOXHDD pDisk, unsigned nImage, PCRTUUID pUuid);
     644 * @param   pDisk           Pointer to HDD container.
     645 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     646 * @param   pUuid           New parent UUID of the image. If NULL, a new UUID is created.
     647 */
     648VBOXDDU_DECL(int) VDSetParentUuid(PVBOXHDD pDisk, unsigned nImage,
     649                                  PCRTUUID pUuid);
    639650
    640651
     
    642653 * Debug helper - dumps all opened images in HDD container into the log file.
    643654 *
    644  * @param   pDisk           Pointer to VBox HDD container.
     655 * @param   pDisk           Pointer to HDD container.
    645656 */
    646657VBOXDDU_DECL(void) VDDumpImages(PVBOXHDD pDisk);
  • trunk/include/VBox/VBoxHDD.h

    r5999 r6291  
    374374
    375375/**
    376  * Get virtual disk geometry stored in image file.
     376 * Get virtual disk PCHS geometry stored in image file.
    377377 *
    378378 * @returns VBox status code.
     
    380380 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
    381381 * @param   pDisk           Pointer to VDI HDD container.
    382  * @param   pcCylinders     Where to store the number of cylinders. NULL is ok.
    383  * @param   pcHeads         Where to store the number of heads. NULL is ok.
    384  * @param   pcSectors       Where to store the number of sectors. NULL is ok.
    385  */
    386 VBOXDDU_DECL(int) VDIDiskGetGeometry(PVDIDISK pDisk, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors);
    387 
    388 /**
    389  * Store virtual disk geometry into base image file of HDD container.
     382 * @param   pPCHSGeometry   Where to store PCHS geometry. Not NULL.
     383 */
     384VBOXDDU_DECL(int) VDIDiskGetPCHSGeometry(PVDIDISK pDisk, PPDMMEDIAGEOMETRY pPCHSGeometry);
     385
     386/**
     387 * Store virtual disk PCHS geometry into base image file of HDD container.
    390388 *
    391389 * Note that in case of unrecoverable error all images of HDD container will be closed.
     
    394392 * @returns VERR_VDI_NOT_OPENED if no one VDI image is opened in HDD container.
    395393 * @param   pDisk           Pointer to VDI HDD container.
    396  * @param   cCylinders      Number of cylinders.
    397  * @param   cHeads          Number of heads.
    398  * @param   cSectors        Number of sectors.
    399  */
    400 VBOXDDU_DECL(int) VDIDiskSetGeometry(PVDIDISK pDisk, unsigned cCylinders, unsigned cHeads, unsigned cSectors);
    401 
    402 /**
    403  * Get virtual disk translation mode stored in image file.
     394 * @param   pPCHSGeometry   Where to store LCHS geometry. Not NULL.
     395 */
     396VBOXDDU_DECL(int) VDIDiskSetPCHSGeometry(PVDIDISK pDisk, PCPDMMEDIAGEOMETRY pPCHSGeometry);
     397
     398/**
     399 * Get virtual disk LCHS geometry stored in image file.
    404400 *
    405401 * @returns VBox status code.
    406402 * @returns VERR_VDI_NOT_OPENED if no one VDI image is opened in HDD container.
    407  * @param   pDisk           Pointer to VDI HDD container.
    408  * @param   penmTranslation Where to store the translation mode (see pdm.h).
    409  */
    410 VBOXDDU_DECL(int) VDIDiskGetTranslation(PVDIDISK pDisk, PPDMBIOSTRANSLATION penmTranslation);
    411 
    412 /**
    413  * Store virtual disk translation mode into base image file of HDD container.
     403 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
     404 * @param   pDisk           Pointer to VDI HDD container.
     405 * @param   pLCHSGeometry   Where to store LCHS geometry. Not NULL.
     406 */
     407VBOXDDU_DECL(int) VDIDiskGetLCHSGeometry(PVDIDISK pDisk, PPDMMEDIAGEOMETRY pLCHSGeometry);
     408
     409/**
     410 * Store virtual disk LCHS geometry into base image file of HDD container.
    414411 *
    415412 * Note that in case of unrecoverable error all images of HDD container will be closed.
     
    418415 * @returns VERR_VDI_NOT_OPENED if no one VDI image is opened in HDD container.
    419416 * @param   pDisk           Pointer to VDI HDD container.
    420  * @param   enmTranslation  Translation mode (see pdm.h).
    421  */
    422 VBOXDDU_DECL(int) VDIDiskSetTranslation(PVDIDISK pDisk, PDMBIOSTRANSLATION enmTranslation);
     417 * @param   pLCHSGeometry   Where to store LCHS geometry. Not NULL.
     418 */
     419VBOXDDU_DECL(int) VDIDiskSetLCHSGeometry(PVDIDISK pDisk, PCPDMMEDIAGEOMETRY pLCHSGeometry);
    423420
    424421/**
  • trunk/include/VBox/log.h

    r6116 r6291  
    146146    /** Host floppy block driver group. */
    147147    LOG_GROUP_DRV_HOST_FLOPPY,
    148     /** Host hard disk (raw partition) media driver group. */
    149     LOG_GROUP_DRV_HOST_HDD,
    150148    /** Host Parallel Driver group */
    151149    LOG_GROUP_DRV_HOST_PARALLEL,
     
    348346    "DRV_HOST_DVD", \
    349347    "DRV_HOST_FLOPPY", \
    350     "DRV_HOST_HDD", \
    351348    "DRV_HOST_PARALLEL", \
    352349    "DRV_HOST_SERIAL", \
  • trunk/include/VBox/pdmifs.h

    r6225 r6291  
    44
    55/*
    6  * Copyright (C) 2006-2007 innotek GmbH
     6 * Copyright (C) 2006-2008 innotek GmbH
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    771771
    772772/**
    773  * BIOS translation mode.
    774  */
    775 typedef enum PDMBIOSTRANSLATION
    776 {
    777     /** No translation. */
    778     PDMBIOSTRANSLATION_NONE = 1,
    779     /** LBA translation. */
    780     PDMBIOSTRANSLATION_LBA,
    781     /** Automatic select mode. */
    782     PDMBIOSTRANSLATION_AUTO
    783 } PDMBIOSTRANSLATION;
    784 
    785 /** Pointer to BIOS translation mode. */
    786 typedef PDMBIOSTRANSLATION *PPDMBIOSTRANSLATION;
     773 * Media geometry structure.
     774 */
     775typedef struct PDMMEDIAGEOMETRY
     776{
     777    /** Number of cylinders. */
     778    uint32_t    cCylinders;
     779    /** Number of heads. */
     780    uint32_t    cHeads;
     781    /** Number of sectors. */
     782    uint32_t    cSectors;
     783} PDMMEDIAGEOMETRY;
     784
     785/** Pointer to media geometry structure. */
     786typedef PDMMEDIAGEOMETRY *PPDMMEDIAGEOMETRY;
     787/** Pointer to constant media geometry structure. */
     788typedef const PDMMEDIAGEOMETRY *PCPDMMEDIAGEOMETRY;
    787789
    788790/** Pointer to a media interface. */
     
    790792/**
    791793 * Media interface.
    792  * Makes up the fundation for PDMIBLOCK and PDMIBLOCKBIOS.
     794 * Makes up the foundation for PDMIBLOCK and PDMIBLOCKBIOS.
    793795 */
    794796typedef struct PDMIMEDIA
     
    847849
    848850    /**
    849      * Get stored media geometry - BIOS property.
     851     * Get stored media geometry (physical CHS, PCHS) - BIOS property.
    850852     * This is an optional feature of a media.
    851853     *
    852854     * @returns VBox status code.
    853855     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    854      * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetGeometry() yet.
    855      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    856      * @param   pcCylinders     Number of cylinders.
    857      * @param   pcHeads         Number of heads.
    858      * @param   pcSectors       Number of sectors. This number is 1-based.
    859      * @remark  This have no influence on the read/write operations.
    860      * @thread  Any thread.
    861      */
    862     DECLR3CALLBACKMEMBER(int, pfnBiosGetGeometry,(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors));
    863 
    864     /**
    865      * Store the media geometry - BIOS property.
     856     * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetPCHSGeometry() yet.
     857     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     858     * @param   pPCHSGeometry   Pointer to PCHS geometry (cylinders/heads/sectors).
     859     * @remark  This has no influence on the read/write operations.
     860     * @thread  Any thread.
     861     */
     862    DECLR3CALLBACKMEMBER(int, pfnBiosGetPCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry));
     863
     864    /**
     865     * Store the media geometry (physical CHS, PCHS) - BIOS property.
    866866     * This is an optional feature of a media.
    867867     *
     
    869869     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    870870     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    871      * @param   cCylinders      Number of cylinders.
    872      * @param   cHeads          Number of heads.
    873      * @param   cSectors        Number of sectors. This number is 1-based.
    874      * @remark  This have no influence on the read/write operations.
    875      * @thread  The emulation thread.
    876      */
    877     DECLR3CALLBACKMEMBER(int, pfnBiosSetGeometry,(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors));
    878 
    879     /**
    880      * Get stored geometry translation mode - BIOS property.
     871     * @param   pPCHSGeometry   Pointer to PCHS geometry (cylinders/heads/sectors).
     872     * @remark  This has no influence on the read/write operations.
     873     * @thread  The emulation thread.
     874     */
     875    DECLR3CALLBACKMEMBER(int, pfnBiosSetPCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry));
     876
     877    /**
     878     * Get stored media geometry (logical CHS, LCHS) - BIOS property.
    881879     * This is an optional feature of a media.
    882880     *
    883881     * @returns VBox status code.
    884      * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry translation mode.
    885      * @returns VERR_PDM_TRANSLATION_NOT_SET if the translation hasn't been set using pfnBiosSetTranslation() yet.
    886      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    887      * @param   penmTranslation Where to store the translation type.
    888      * @remark  This have no influence on the read/write operations.
    889      * @thread  Any thread.
    890      */
    891     DECLR3CALLBACKMEMBER(int, pfnBiosGetTranslation,(PPDMIMEDIA pInterface, PPDMBIOSTRANSLATION penmTranslation));
    892 
    893     /**
    894      * Store media geometry - BIOS property.
     882     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
     883     * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetLCHSGeometry() yet.
     884     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     885     * @param   pLCHSGeometry   Pointer to LCHS geometry (cylinders/heads/sectors).
     886     * @remark  This has no influence on the read/write operations.
     887     * @thread  Any thread.
     888     */
     889    DECLR3CALLBACKMEMBER(int, pfnBiosGetLCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry));
     890
     891    /**
     892     * Store the media geometry (logical CHS, LCHS) - BIOS property.
    895893     * This is an optional feature of a media.
    896894     *
     
    898896     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    899897     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    900      * @param   enmTranslation  The translation type.
    901      * @remark  This have no influence on the read/write operations.
    902      * @thread  The emulation thread.
    903      */
    904     DECLR3CALLBACKMEMBER(int, pfnBiosSetTranslation,(PPDMIMEDIA pInterface, PDMBIOSTRANSLATION enmTranslation));
     898     * @param   pLCHSGeometry   Pointer to LCHS geometry (cylinders/heads/sectors).
     899     * @remark  This has no influence on the read/write operations.
     900     * @thread  The emulation thread.
     901     */
     902    DECLR3CALLBACKMEMBER(int, pfnBiosSetLCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry));
    905903
    906904    /**
     
    926924{
    927925    /**
    928      * Get stored media geometry - BIOS property.
     926     * Get stored media geometry (physical CHS, PCHS) - BIOS property.
    929927     * This is an optional feature of a media.
    930928     *
    931929     * @returns VBox status code.
    932930     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    933      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    934      * @param   pcCylinders     Number of cylinders.
    935      * @param   pcHeads         Number of heads.
    936      * @param   pcSectors       Number of sectors. This number is 1-based.
    937      * @remark  This have no influence on the read/write operations.
    938      * @thread  Any thread.
    939      */
    940     DECLR3CALLBACKMEMBER(int, pfnGetGeometry,(PPDMIBLOCKBIOS pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors));
    941 
    942     /**
    943      * Store the media geometry - BIOS property.
     931     * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnSetPCHSGeometry() yet.
     932     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     933     * @param   pPCHSGeometry   Pointer to PCHS geometry (cylinders/heads/sectors).
     934     * @remark  This has no influence on the read/write operations.
     935     * @thread  Any thread.
     936     */
     937    DECLR3CALLBACKMEMBER(int, pfnGetPCHSGeometry,(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry));
     938
     939    /**
     940     * Store the media geometry (physical CHS, PCHS) - BIOS property.
    944941     * This is an optional feature of a media.
    945942     *
     
    947944     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    948945     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    949      * @param   cCylinders      Number of cylinders.
    950      * @param   cHeads          Number of heads.
    951      * @param   cSectors        Number of sectors. This number is 1-based.
    952      * @remark  This have no influence on the read/write operations.
    953      * @thread  The emulation thread.
    954      */
    955     DECLR3CALLBACKMEMBER(int, pfnSetGeometry,(PPDMIBLOCKBIOS pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors));
    956 
    957     /**
    958      * Get stored geometry translation mode - BIOS property.
     946     * @param   pPCHSGeometry   Pointer to PCHS geometry (cylinders/heads/sectors).
     947     * @remark  This has no influence on the read/write operations.
     948     * @thread  The emulation thread.
     949     */
     950    DECLR3CALLBACKMEMBER(int, pfnSetPCHSGeometry,(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry));
     951
     952    /**
     953     * Get stored media geometry (logical CHS, LCHS) - BIOS property.
    959954     * This is an optional feature of a media.
    960955     *
    961956     * @returns VBox status code.
    962      * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry translation mode.
    963      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    964      * @param   penmTranslation Where to store the translation type.
    965      * @remark  This have no influence on the read/write operations.
    966      * @thread  Any thread.
    967      */
    968     DECLR3CALLBACKMEMBER(int, pfnGetTranslation,(PPDMIBLOCKBIOS pInterface, PPDMBIOSTRANSLATION penmTranslation));
    969 
    970     /**
    971      * Store media geometry - BIOS property.
     957     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
     958     * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnSetLCHSGeometry() yet.
     959     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     960     * @param   pLCHSGeometry   Pointer to LCHS geometry (cylinders/heads/sectors).
     961     * @remark  This has no influence on the read/write operations.
     962     * @thread  Any thread.
     963     */
     964    DECLR3CALLBACKMEMBER(int, pfnGetLCHSGeometry,(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry));
     965
     966    /**
     967     * Store the media geometry (logical CHS, LCHS) - BIOS property.
    972968     * This is an optional feature of a media.
    973969     *
     
    975971     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    976972     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    977      * @param   enmTranslation  The translation type.
    978      * @remark  This have no influence on the read/write operations.
    979      * @thread  The emulation thread.
    980      */
    981     DECLR3CALLBACKMEMBER(int, pfnSetTranslation,(PPDMIBLOCKBIOS pInterface, PDMBIOSTRANSLATION enmTranslation));
     973     * @param   pLCHSGeometry   Pointer to LCHS geometry (cylinders/heads/sectors).
     974     * @remark  This has no influence on the read/write operations.
     975     * @thread  The emulation thread.
     976     */
     977    DECLR3CALLBACKMEMBER(int, pfnSetLCHSGeometry,(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry));
    982978
    983979    /**
     
    13231319
    13241320    /**
    1325      * Get stored media geometry - BIOS property.
     1321     * Get stored media geometry (physical CHS, PCHS) - BIOS property.
    13261322     * This is an optional feature of a media.
    13271323     *
    13281324     * @returns VBox status code.
    13291325     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    1330      * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetGeometry() yet.
    1331      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1332      * @param   pcCylinders     Number of cylinders.
    1333      * @param   pcHeads         Number of heads.
    1334      * @param   pcSectors       Number of sectors. This number is 1-based.
    1335      * @remark  This have no influence on the read/write operations.
    1336      * @thread  Any thread.
    1337      */
    1338     DECLR3CALLBACKMEMBER(int, pfnBiosGetGeometry,(PPDMIMEDIAASYNC pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors));
    1339 
    1340     /**
    1341      * Store the media geometry - BIOS property.
     1326     * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetPCHSGeometry() yet.
     1327     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     1328     * @param   pPCHSGeometry   Pointer to PCHS geometry (cylinders/heads/sectors).
     1329     * @remark  This has no influence on the read/write operations.
     1330     * @thread  Any thread.
     1331     */
     1332    DECLR3CALLBACKMEMBER(int, pfnBiosGetPCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry));
     1333
     1334    /**
     1335     * Store the media geometry (physical CHS, PCHS) - BIOS property.
    13421336     * This is an optional feature of a media.
    13431337     *
     
    13451339     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    13461340     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1347      * @param   cCylinders      Number of cylinders.
    1348      * @param   cHeads          Number of heads.
    1349      * @param   cSectors        Number of sectors. This number is 1-based.
    1350      * @remark  This have no influence on the read/write operations.
    1351      * @thread  The emulation thread.
    1352      */
    1353     DECLR3CALLBACKMEMBER(int, pfnBiosSetGeometry,(PPDMIMEDIAASYNC pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors));
    1354 
    1355     /**
    1356      * Get stored geometry translation mode - BIOS property.
     1341     * @param   pPCHSGeometry   Pointer to PCHS geometry (cylinders/heads/sectors).
     1342     * @remark  This has no influence on the read/write operations.
     1343     * @thread  The emulation thread.
     1344     */
     1345    DECLR3CALLBACKMEMBER(int, pfnBiosSetPCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry));
     1346
     1347    /**
     1348     * Get stored media geometry (logical CHS, LCHS) - BIOS property.
    13571349     * This is an optional feature of a media.
    13581350     *
    13591351     * @returns VBox status code.
    1360      * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry translation mode.
    1361      * @returns VERR_PDM_TRANSLATION_NOT_SET if the translation hasn't been set using pfnBiosSetTranslation() yet.
    1362      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1363      * @param   penmTranslation Where to store the translation type.
    1364      * @remark  This have no influence on the read/write operations.
    1365      * @thread  Any thread.
    1366      */
    1367     DECLR3CALLBACKMEMBER(int, pfnBiosGetTranslation,(PPDMIMEDIAASYNC pInterface, PPDMBIOSTRANSLATION penmTranslation));
    1368 
    1369     /**
    1370      * Store media geometry - BIOS property.
     1352     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
     1353     * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetLCHSGeometry() yet.
     1354     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     1355     * @param   pLCHSGeometry   Pointer to LCHS geometry (cylinders/heads/sectors).
     1356     * @remark  This has no influence on the read/write operations.
     1357     * @thread  Any thread.
     1358     */
     1359    DECLR3CALLBACKMEMBER(int, pfnBiosGetLCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry));
     1360
     1361    /**
     1362     * Store the media geometry (logical CHS, LCHS) - BIOS property.
    13711363     * This is an optional feature of a media.
    13721364     *
     
    13741366     * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry.
    13751367     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1376      * @param   enmTranslation  The translation type.
    1377      * @remark  This have no influence on the read/write operations.
    1378      * @thread  The emulation thread.
    1379      */
    1380     DECLR3CALLBACKMEMBER(int, pfnBiosSetTranslation,(PPDMIMEDIAASYNC pInterface, PDMBIOSTRANSLATION enmTranslation));
     1368     * @param   pLCHSGeometry   Pointer to LCHS geometry (cylinders/heads/sectors).
     1369     * @remark  This has no influence on the read/write operations.
     1370     * @thread  The emulation thread.
     1371     */
     1372    DECLR3CALLBACKMEMBER(int, pfnBiosSetLCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry));
    13811373
    13821374    /**
     
    16321624/**
    16331625 * Stream interface.
    1634  * Makes up the fundation for PDMICHAR.
     1626 * Makes up the foundation for PDMICHAR.
    16351627 */
    16361628typedef struct PDMISTREAM
  • trunk/src/VBox/Devices/Builtins.cpp

    r5999 r6291  
    55
    66/*
    7  * Copyright (C) 2006-2007 innotek GmbH
     7 * Copyright (C) 2006-2008 innotek GmbH
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    172172    if (VBOX_FAILURE(rc))
    173173        return rc;
    174 #ifndef RT_OS_L4
    175     rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvVmdkHDD);
    176     if (VBOX_FAILURE(rc))
    177         return rc;
    178 #endif
    179174#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
    180175    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostDVD);
     
    193188    if (VBOX_FAILURE(rc))
    194189        return rc;
    195 #if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
    196     rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvHostHDD);
    197     if (VBOX_FAILURE(rc))
    198         return rc;
    199 #endif
    200190#ifdef VBOX_WITH_ISCSI
    201191    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvISCSI);
  • trunk/src/VBox/Devices/Builtins.h

    r5999 r6291  
    6565extern const PDMDRVREG g_DrvVBoxHDD;
    6666extern const PDMDRVREG g_DrvVD;
    67 extern const PDMDRVREG g_DrvVmdkHDD;
    6867extern const PDMDRVREG g_DrvHostDVD;
    6968extern const PDMDRVREG g_DrvHostFloppy;
    7069extern const PDMDRVREG g_DrvMediaISO;
    7170extern const PDMDRVREG g_DrvRawImage;
    72 extern const PDMDRVREG g_DrvHostHDD;
    7371extern const PDMDRVREG g_DrvISCSI;
    7472extern const PDMDRVREG g_DrvISCSITransportTcp;
  • trunk/src/VBox/Devices/Makefile.kmk

    r6221 r6291  
    492492        Storage/DrvHostDVD.cpp \
    493493        Storage/DrvHostFloppy.cpp \
    494         Storage/DrvHostRawDisk.cpp \
    495494        Storage/DrvMediaISO.cpp \
    496495        Storage/DrvRawImage.cpp \
    497496        Storage/DrvVD.cpp \
    498         Storage/DrvVmdk.cpp \
    499497        Storage/VBoxHDD.cpp
    500498
     
    564562        Network/DrvTAP.cpp \
    565563        Storage/DrvHostBase.cpp \
    566         Storage/DrvHostDVD.cpp \
    567         Storage/DrvHostRawDisk.cpp
     564        Storage/DrvHostDVD.cpp
    568565 ifdef VBOX_WITH_CROSSBOW
    569566  Drivers_DEFS += VBOX_WITH_CROSSBOW
  • trunk/src/VBox/Devices/PC/BIOS/rombios.c

    r5757 r6291  
    9393//   - EBDA segment.
    9494//     I used memory starting at 0x121 in the segment
     95#ifndef VBOX
    9596//   - the translation policy is defined in cmos regs 0x39 & 0x3a
     97#endif /* !VBOX */
    9698//
    9799// TODO :
     
    202204#if BX_APM && BX_CPU<3
    203205#    error APM BIOS can only be used with 386+ cpu
     206#endif
     207
     208#if defined(VBOX) && !BX_USE_ATADRV
     209#    error VBOX requires enabling the ATA/ATAPI driver
    204210#endif
    205211
     
    23902396      Bit32u sectors;
    23912397      Bit16u cylinders, heads, spt, blksize;
     2398#ifdef VBOX
     2399      Bit16u lcylinders, lheads, lspt;
     2400      Bit8u chsgeo_base;
     2401#endif /* VBOX */
    23922402      Bit8u  translation, removable, mode;
    23932403
     
    24162426      if (sectors == 268435455)
    24172427        sectors = read_dword(get_SS(),buffer+(100*2)); // words 100 to 103 (someday)
     2428      switch (device)
     2429      {
     2430          case 0:
     2431              chsgeo_base = 0x1e;
     2432              break;
     2433          case 1:
     2434              chsgeo_base = 0x26;
     2435              break;
     2436          case 2:
     2437              chsgeo_base = 0x67;
     2438              break;
     2439          case 3:
     2440              chsgeo_base = 0x70;
     2441              break;
     2442          default:
     2443              chsgeo_base = 0;
     2444      }
     2445      if (chsgeo_base != 0)
     2446      {
     2447          lcylinders = inb_cmos(chsgeo_base) + (inb_cmos(chsgeo_base+1) << 8);
     2448          lheads = inb_cmos(chsgeo_base+2);
     2449          lspt = inb_cmos(chsgeo_base+7);
     2450      }
     2451      else
     2452      {
     2453          lcylinders = 0;
     2454          lheads = 0;
     2455          lspt = 0;
     2456      }
    24182457#endif /* VBOX */
    24192458
     
    24262465      write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
    24272466      write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
     2467#ifdef VBOX
     2468      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, lheads);
     2469      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, lcylinders);
     2470      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, lspt);
     2471#else /* !VBOX */
    24282472      BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
    24292473
     
    24362480      switch (translation) {
    24372481        case ATA_TRANSLATION_NONE:
    2438 #ifndef VBOX
    24392482          BX_INFO("none");
    2440 #else /* VBOX */
    2441           bios_printf(BIOS_PRINTF_INFO, "none");
    2442 #endif /* VBOX */
    24432483          break;
    24442484        case ATA_TRANSLATION_LBA:
    2445 #ifndef VBOX
    24462485          BX_INFO("lba");
    2447 #else /* VBOX */
    2448           bios_printf(BIOS_PRINTF_INFO, "lba");
    2449 #endif /* VBOX */
    24502486          break;
    24512487        case ATA_TRANSLATION_LARGE:
    2452 #ifndef VBOX
    24532488          BX_INFO("large");
    2454 #else /* VBOX */
    2455           bios_printf(BIOS_PRINTF_INFO, "large");
    2456 #endif /* VBOX */
    24572489          break;
    24582490        case ATA_TRANSLATION_RECHS:
    2459 #ifndef VBOX
    24602491          BX_INFO("r-echs");
    2461 #else /* VBOX */
    2462           bios_printf(BIOS_PRINTF_INFO, "r-echs");
    2463 #endif /* VBOX */
    24642492          break;
    24652493        }
     
    24982526      // clip to 1024 cylinders in lchs
    24992527      if (cylinders > 1024) cylinders=1024;
    2500 #ifndef VBOX
    25012528      BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
    2502 #else /* VBOX */
    2503       bios_printf(BIOS_PRINTF_INFO, " LCHS=%d/%d/%d\n", cylinders, heads, spt);
    2504 #endif /* VBOX */
    25052529
    25062530      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
    25072531      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
    25082532      write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
     2533#endif /* VBOX */
    25092534
    25102535      // fill hdidmap
  • trunk/src/VBox/Devices/PC/DevPcBios.cpp

    r5999 r6291  
    55
    66/*
    7  * Copyright (C) 2006-2007 innotek GmbH
     7 * Copyright (C) 2006-2008 innotek GmbH
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    265265__END_DECLS
    266266
     267/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
     268 * record (partition table). */
     269static int biosGuessDiskLCHS(PPDMIBLOCK pBlock, PPDMMEDIAGEOMETRY pLCHSGeometry)
     270{
     271    uint8_t aMBR[512], *p;
     272    int rc;
     273    uint32_t iEndHead, iEndSector, cLCHSCylinders, cLCHSHeads, cLCHSSectors;
     274
     275    if (!pBlock)
     276        return VERR_INVALID_PARAMETER;
     277    rc = pBlock->pfnRead(pBlock, 0, aMBR, sizeof(aMBR));
     278    if (VBOX_FAILURE(rc))
     279        return rc;
     280    /* Test MBR magic number. */
     281    if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
     282        return VERR_INVALID_PARAMETER;
     283    for (uint32_t i = 0; i < 4; i++)
     284    {
     285        /* Figure out the start of a partition table entry. */
     286        p = &aMBR[0x1be + i * 16];
     287        iEndHead = p[5];
     288        iEndSector = p[6] & 63;
     289        if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
     290        {
     291            /* Assumption: partition terminates on a cylinder boundary. */
     292            cLCHSHeads = iEndHead + 1;
     293            cLCHSSectors = iEndSector;
     294            cLCHSCylinders = pBlock->pfnGetSize(pBlock) / (512 * cLCHSHeads * cLCHSSectors);
     295            if (cLCHSCylinders >= 1)
     296            {
     297                pLCHSGeometry->cCylinders = cLCHSCylinders;
     298                pLCHSGeometry->cHeads = cLCHSHeads;
     299                pLCHSGeometry->cSectors = cLCHSSectors;
     300                Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cLCHSCylinders, cLCHSHeads, cLCHSSectors));
     301                return VINF_SUCCESS;
     302            }
     303        }
     304    }
     305    return VERR_INVALID_PARAMETER;
     306}
     307
    267308
    268309/**
     
    293334static void pcbiosCmosInitHardDisk(PPDMDEVINS pDevIns, int offType, int offInfo, PPDMIBLOCKBIOS pBlockBios)
    294335{
    295     if (    pBlockBios->pfnGetType(pBlockBios) == PDMBLOCKTYPE_HARD_DISK
    296         &&  pBlockBios->pfnIsVisible(pBlockBios))
    297     {
    298         uint32_t    cCylinders;
    299         uint32_t    cHeads;
    300         uint32_t    cSectors;
    301         int rc = pBlockBios->pfnGetGeometry(pBlockBios, &cCylinders, &cHeads, &cSectors);
    302         if (VBOX_SUCCESS(rc))
    303         {
    304             Log2(("pcbiosCmosInitHardDisk: offInfo=%#x: CHS=%d/%d/%d\n", offInfo, cCylinders, cHeads, cSectors));
    305             pcbiosCmosWrite(pDevIns, offType, 47);                              /* 19h - First Extended Hard Disk Drive Type */
    306             pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(cCylinders, 16383) & 0xff); /* 1Bh - (AMI) First Hard Disk (type 47) user defined: # of Cylinders, LSB */
    307             pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(cCylinders, 16383) >> 8); /* 1Ch - (AMI) First Hard Disk user defined: # of Cylinders, High Byte */
    308             pcbiosCmosWrite(pDevIns, offInfo + 2, cHeads);                      /* 1Dh - (AMI) First Hard Disk user defined: Number of Heads */
    309             pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);                        /* 1Eh - (AMI) First Hard Disk user defined: Write Precompensation Cylinder, Low Byte */
    310             pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);                        /* 1Fh - (AMI) First Hard Disk user defined: Write Precompensation Cylinder, High Byte */
    311             pcbiosCmosWrite(pDevIns, offInfo + 5, 0xc0 | ((cHeads > 8) << 3));  /* 20h - (AMI) First Hard Disk user defined: Control Byte */
    312             pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);                        /* 21h - (AMI) First Hard Disk user defined: Landing Zone, Low Byte */
    313             pcbiosCmosWrite(pDevIns, offInfo + 7, 0xff);                        /* 22h - (AMI) First Hard Disk user defined: Landing Zone, High Byte */
    314             pcbiosCmosWrite(pDevIns, offInfo + 8, cSectors);                    /* 23h - (AMI) First Hard Disk user defined: # of Sectors per track */
    315             return;
    316         }
    317     }
    318     pcbiosCmosWrite(pDevIns, offType, 0);
     336    PDMMEDIAGEOMETRY LCHSGeometry;
     337    int rc = pBlockBios->pfnGetLCHSGeometry(pBlockBios, &LCHSGeometry);
     338    if (VBOX_SUCCESS(rc))
     339    {
     340        Log2(("%s: offInfo=%#x: LCHS=%d/%d/%d\n", __FUNCTION__, offInfo, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
     341        if (offType)
     342            pcbiosCmosWrite(pDevIns, offType, 48);
     343        /* Cylinders low */
     344        pcbiosCmosWrite(pDevIns, offInfo + 0, RT_MIN(LCHSGeometry.cCylinders, 1024) & 0xff);
     345        /* Cylinders high */
     346        pcbiosCmosWrite(pDevIns, offInfo + 1, RT_MIN(LCHSGeometry.cCylinders, 1024) >> 8);
     347        /* Heads */
     348        pcbiosCmosWrite(pDevIns, offInfo + 2, LCHSGeometry.cHeads);
     349        /* Landing zone low */
     350        pcbiosCmosWrite(pDevIns, offInfo + 3, 0xff);
     351        /* Landing zone high */
     352        pcbiosCmosWrite(pDevIns, offInfo + 4, 0xff);
     353        /* Write precomp low */
     354        pcbiosCmosWrite(pDevIns, offInfo + 5, 0xff);
     355        /* Write precomp high */
     356        pcbiosCmosWrite(pDevIns, offInfo + 6, 0xff);
     357        /* Sectors */
     358        pcbiosCmosWrite(pDevIns, offInfo + 7, LCHSGeometry.cSectors);
     359        return;
     360    }
     361    if (offType)
     362        pcbiosCmosWrite(pDevIns, offType, 0);
    319363}
    320364
     
    450494    switch (u32)
    451495    {
    452         case 1: u32 = 0x01; break;      /* floppy installed, 1 drive. */
    453         case 2: u32 = 0x41; break;      /* floppy installed, 2 drives. */
     496        case 1: u32 = 0x01; break;      /* floppy installed, 2 drives. */
    454497        default:u32 = 0;    break;      /* floppy not installed. */
    455498    }
     
    468511        if (VBOX_SUCCESS(rc))
    469512            apHDs[i] = (PPDMIBLOCKBIOS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK_BIOS);
    470     }
    471 
    472     u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);                        /* 0Fh means extended and points to 1Ah, 1Bh */
    473     pcbiosCmosWrite(pDevIns, 0x12, u32);                                        /* 12h - Hard Disk Data (type) */
    474     if (apHDs[0])
    475         pcbiosCmosInitHardDisk(pDevIns, 0x19, 0x1b, apHDs[0]);                  /* 19h - First Extended Hard Disk Drive Type */
    476     if (apHDs[1])
    477         pcbiosCmosInitHardDisk(pDevIns, 0x1a, 0x24, apHDs[1]);                  /* 1Ah - Second Extended Hard Disk Drive Type */
    478 
    479     /*
    480      * Translation type - Bochs BIOS specific.
    481      */
    482     u32 = 0;
    483     for (i = 0; i < 4; i++)
    484     {
     513        if (   apHDs[i]
     514            && (   apHDs[i]->pfnGetType(apHDs[i]) != PDMBLOCKTYPE_HARD_DISK
     515                || !apHDs[i]->pfnIsVisible(apHDs[i])))
     516            apHDs[i] = NULL;
    485517        if (apHDs[i])
    486518        {
    487             PDMBIOSTRANSLATION enmTranslation;
    488             int rc = apHDs[i]->pfnGetTranslation(apHDs[i], &enmTranslation);
    489             if (VBOX_FAILURE(rc) || enmTranslation == PDMBIOSTRANSLATION_AUTO)
     519            PDMMEDIAGEOMETRY LCHSGeometry;
     520            int rc = apHDs[i]->pfnGetLCHSGeometry(apHDs[i], &LCHSGeometry);
     521            if (   rc == VERR_PDM_GEOMETRY_NOT_SET
     522                || LCHSGeometry.cCylinders == 0
     523                || LCHSGeometry.cCylinders > 1024
     524                || LCHSGeometry.cHeads == 0
     525                || LCHSGeometry.cHeads > 255
     526                || LCHSGeometry.cSectors == 0
     527                || LCHSGeometry.cSectors > 63)
    490528            {
    491                 uint32_t cCylinders, cHeads, cSectors;
    492                 rc = apHDs[i]->pfnGetGeometry(apHDs[i], &cCylinders, &cHeads, &cSectors);
     529                PPDMIBLOCK pBlock;
     530                pBlock = (PPDMIBLOCK)pBase->pfnQueryInterface(pBase, PDMINTERFACE_BLOCK);
     531                /* No LCHS geometry, autodetect and set. */
     532                rc = biosGuessDiskLCHS(pBlock, &LCHSGeometry);
    493533                if (VBOX_FAILURE(rc))
    494534                {
    495                     AssertMsg(rc == VERR_PDM_MEDIA_NOT_MOUNTED, ("This shouldn't happen! rc=%Vrc\n", rc));
    496                     enmTranslation = PDMBIOSTRANSLATION_NONE;
     535                    /* Try if PCHS geometry works, otherwise fall back. */
     536                    rc = apHDs[i]->pfnGetPCHSGeometry(apHDs[i], &LCHSGeometry);
    497537                }
    498                 else if (cCylinders <= 1024 && cHeads <= 16 && cSectors <= 63)
     538                if (   VBOX_FAILURE(rc)
     539                    || LCHSGeometry.cCylinders == 0
     540                    || LCHSGeometry.cCylinders > 1024
     541                    || LCHSGeometry.cHeads == 0
     542                    || LCHSGeometry.cHeads > 16
     543                    || LCHSGeometry.cSectors == 0
     544                    || LCHSGeometry.cSectors > 63)
    499545                {
    500                     /* Disk <= 512 MByte not needing LBA translation. */
    501                     enmTranslation = PDMBIOSTRANSLATION_NONE;
     546                    uint64_t cSectors = pBlock->pfnGetSize(pBlock) / 512;
     547                    if (cSectors / 16 / 63 <= 1024)
     548                    {
     549                        LCHSGeometry.cCylinders = RT_MAX(cSectors / 16 / 63, 1);
     550                        LCHSGeometry.cHeads = 16;
     551                    }
     552                    else if (cSectors / 32 / 63 <= 1024)
     553                    {
     554                        LCHSGeometry.cCylinders = RT_MAX(cSectors / 32 / 63, 1);
     555                        LCHSGeometry.cHeads = 32;
     556                    }
     557                    else if (cSectors / 64 / 63 <= 1024)
     558                    {
     559                        LCHSGeometry.cCylinders = cSectors / 64 / 63;
     560                        LCHSGeometry.cHeads = 64;
     561                    }
     562                    else if (cSectors / 128 / 63 <= 1024)
     563                    {
     564                        LCHSGeometry.cCylinders = cSectors / 128 / 63;
     565                        LCHSGeometry.cHeads = 128;
     566                    }
     567                    else
     568                    {
     569                        LCHSGeometry.cCylinders = RT_MIN(cSectors / 255 / 63, 1024);
     570                        LCHSGeometry.cHeads = 255;
     571                    }
     572                    LCHSGeometry.cSectors = 63;
     573
    502574                }
    503                 else if (cSectors != 63 || (cHeads != 16 && cHeads != 32 && cHeads != 64 && cHeads != 128 && cHeads != 255))
    504                 {
    505                     /* Disk with strange geometry. Using LBA here can
    506                      * break booting of the guest OS. Especially operating
    507                      * systems from Microsoft are sensitive to BIOS CHS not
    508                      * matching what the partition table says. */
    509                     enmTranslation = PDMBIOSTRANSLATION_NONE;
    510                 }
    511                 else
    512                     enmTranslation = PDMBIOSTRANSLATION_LBA;
     575                rc = apHDs[i]->pfnSetLCHSGeometry(apHDs[i], &LCHSGeometry);
     576                AssertRC(rc);
    513577            }
    514             switch (enmTranslation)
    515             {
    516                 case PDMBIOSTRANSLATION_AUTO: /* makes gcc happy */
    517                 case PDMBIOSTRANSLATION_NONE:
    518                     /* u32 |= 0 << (i * 2) */
    519                     break;
    520                 default:
    521                     AssertMsgFailed(("bad enmTranslation=%d\n", enmTranslation));
    522                 case PDMBIOSTRANSLATION_LBA:
    523                     u32 |= 1 << (i * 2);
    524                     break;
    525             }
    526         }
    527     }
    528     Log2(("pcbiosInitComplete: translation byte: %#02x\n", u32));
    529     pcbiosCmosWrite(pDevIns, 0x39, u32);
    530 
    531     LogFlow(("pcbiosInitComplete: returns VINF_SUCCESS\n"));
     578            LogRel(("DevPcBios: ATA LUN#%d LCHS=%u/%u/%u\n", i, LCHSGeometry.cCylinders, LCHSGeometry.cHeads, LCHSGeometry.cSectors));
     579            pcbiosCmosWrite(pDevIns, 0x40 + i * 4, LCHSGeometry.cCylinders & 0xff);
     580            pcbiosCmosWrite(pDevIns, 0x41 + i * 4, LCHSGeometry.cCylinders >> 8);
     581            pcbiosCmosWrite(pDevIns, 0x42 + i * 4, LCHSGeometry.cHeads & 0xff);
     582            pcbiosCmosWrite(pDevIns, 0x43 + i * 4, LCHSGeometry.cSectors & 0xff);
     583        }
     584    }
     585
     586    /* 0Fh means extended and points to 19h, 1Ah */
     587    u32 = (apHDs[0] ? 0xf0 : 0) | (apHDs[1] ? 0x0f : 0);
     588    pcbiosCmosWrite(pDevIns, 0x12, u32);
     589    /* Award BIOS extended drive types for first and second disk, and
     590     * extended drive types for third and fourth disk. Used by the BIOS. */
     591    if (apHDs[0])
     592        pcbiosCmosInitHardDisk(pDevIns, 0x19, 0x1e, apHDs[0]);
     593    if (apHDs[1])
     594        pcbiosCmosInitHardDisk(pDevIns, 0x1a, 0x26, apHDs[1]);
     595    if (apHDs[2])
     596        pcbiosCmosInitHardDisk(pDevIns, 0x00, 0x67, apHDs[2]);
     597    if (apHDs[3])
     598        pcbiosCmosInitHardDisk(pDevIns, 0x00, 0x70, apHDs[3]);
     599
     600    LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
    532601    return VINF_SUCCESS;
    533602}
  • trunk/src/VBox/Devices/Storage/DevATA.cpp

    r6062 r6291  
    66
    77/*
    8  * Copyright (C) 2006-2007 innotek GmbH
     8 * Copyright (C) 2006-2008 innotek GmbH
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    8484    uint8_t cMultSectors;
    8585    /** PCHS disk geometry. */
    86     uint32_t cCHSCylinders, cCHSHeads, cCHSSectors;
     86    PDMMEDIAGEOMETRY PCHSGeometry;
    8787    /** Total number of sectors on this disk. */
    8888    uint64_t cTotalSectors;
     
    10621062    memset(p, 0, 512);
    10631063    p[0] = RT_H2LE_U16(0x0040);
    1064     p[1] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383));
    1065     p[3] = RT_H2LE_U16(s->cCHSHeads);
     1064    p[1] = RT_H2LE_U16(RT_MIN(s->PCHSGeometry.cCylinders, 16383));
     1065    p[3] = RT_H2LE_U16(s->PCHSGeometry.cHeads);
    10661066    /* Block size; obsolete, but required for the BIOS. */
    10671067    p[5] = RT_H2LE_U16(512);
    1068     p[6] = RT_H2LE_U16(s->cCHSSectors);
     1068    p[6] = RT_H2LE_U16(s->PCHSGeometry.cSectors);
    10691069    ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
    10701070    p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
     
    10821082    p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
    10831083    p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
    1084     p[54] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383));
    1085     p[55] = RT_H2LE_U16(s->cCHSHeads);
    1086     p[56] = RT_H2LE_U16(s->cCHSSectors);
    1087     p[57] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383) * s->cCHSHeads * s->cCHSSectors);
    1088     p[58] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383) * s->cCHSHeads * s->cCHSSectors >> 16);
     1084    p[54] = RT_H2LE_U16(RT_MIN(s->PCHSGeometry.cCylinders, 16383));
     1085    p[55] = RT_H2LE_U16(s->PCHSGeometry.cHeads);
     1086    p[56] = RT_H2LE_U16(s->PCHSGeometry.cSectors);
     1087    p[57] = RT_H2LE_U16(  RT_MIN(s->PCHSGeometry.cCylinders, 16383)
     1088                        * s->PCHSGeometry.cHeads
     1089                        * s->PCHSGeometry.cSectors);
     1090    p[58] = RT_H2LE_U16(  RT_MIN(s->PCHSGeometry.cCylinders, 16383)
     1091                        * s->PCHSGeometry.cHeads
     1092                        * s->PCHSGeometry.cSectors >> 16);
    10891093    if (s->cMultSectors)
    10901094        p[59] = RT_H2LE_U16(0x100 | s->cMultSectors);
     
    12681272    {
    12691273        /* CHS */
    1270         iLBA = ((s->uATARegHCyl << 8) | s->uATARegLCyl) * s->cCHSHeads * s->cCHSSectors +
    1271             (s->uATARegSelect & 0x0f) * s->cCHSSectors +
     1274        iLBA = ((s->uATARegHCyl << 8) | s->uATARegLCyl) * s->PCHSGeometry.cHeads * s->PCHSGeometry.cSectors +
     1275            (s->uATARegSelect & 0x0f) * s->PCHSGeometry.cSectors +
    12721276            (s->uATARegSector - 1);
    12731277    }
     
    13031307    {
    13041308        /* CHS */
    1305         cyl = iLBA / (s->cCHSHeads * s->cCHSSectors);
    1306         r = iLBA % (s->cCHSHeads * s->cCHSSectors);
     1309        cyl = iLBA / (s->PCHSGeometry.cHeads * s->PCHSGeometry.cSectors);
     1310        r = iLBA % (s->PCHSGeometry.cHeads * s->PCHSGeometry.cSectors);
    13071311        s->uATARegHCyl = cyl >> 8;
    13081312        s->uATARegLCyl = cyl;
    1309         s->uATARegSelect = (s->uATARegSelect & 0xf0) | ((r / s->cCHSSectors) & 0x0f);
    1310         s->uATARegSector = (r % s->cCHSSectors) + 1;
     1313        s->uATARegSelect = (s->uATARegSelect & 0xf0) | ((r / s->PCHSGeometry.cSectors) & 0x0f);
     1314        s->uATARegSector = (r % s->PCHSGeometry.cSectors) + 1;
    13111315    }
    13121316}
     
    38683872#ifdef IN_RING3
    38693873
    3870 /* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
    3871  * record (partition table). */
    3872 static int ataGuessDiskLCHS(ATADevState *s, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
    3873 {
    3874     uint8_t aMBR[512], *p;
    3875     int rc;
    3876     uint32_t iEndHead, iEndSector, cCHSCylinders, cCHSHeads, cCHSSectors;
    3877 
    3878     if (s->fATAPI || !s->pDrvBlock)
    3879         return VERR_INVALID_PARAMETER;
    3880     rc = s->pDrvBlock->pfnRead(s->pDrvBlock, 0, aMBR, 1 * 512);
    3881     if (VBOX_FAILURE(rc))
    3882         return rc;
    3883     /* Test MBR magic number. */
    3884     if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
    3885         return VERR_INVALID_PARAMETER;
    3886     for (uint32_t i = 0; i < 4; i++)
    3887     {
    3888         /* Figure out the start of a partition table entry. */
    3889         p = &aMBR[0x1be + i * 16];
    3890         iEndHead = p[5];
    3891         iEndSector = p[6] & 63;
    3892         if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
    3893         {
    3894             /* Assumption: partition terminates on a cylinder boundary. */
    3895             cCHSHeads = iEndHead + 1;
    3896             cCHSSectors = iEndSector;
    3897             cCHSCylinders = s->cTotalSectors / (cCHSHeads * cCHSSectors);
    3898             if (cCHSCylinders >= 1)
    3899             {
    3900                 *pcHeads = cCHSHeads;
    3901                 *pcSectors = cCHSSectors;
    3902                 *pcCylinders = cCHSCylinders;
    3903                 Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cCHSCylinders, cCHSHeads, cCHSSectors));
    3904                 return VINF_SUCCESS;
    3905             }
    3906         }
    3907     }
    3908     return VERR_INVALID_PARAMETER;
    3909 }
    3910 
    3911 
    39123874static void ataDMATransferStop(ATADevState *s)
    39133875{
     
    54475409
    54485410    /*
    5449      * Init geometry.
     5411     * Init geometry (only for non-CD/DVD media).
    54505412     */
    54515413    if (pIf->fATAPI)
    54525414    {
    54535415        pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 2048;
    5454         rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
    5455         pIf->cCHSCylinders = 0; /* dummy */
    5456         pIf->cCHSHeads     = 0; /* dummy */
    5457         pIf->cCHSSectors   = 0; /* dummy */
    5458         if (rc != VERR_PDM_MEDIA_NOT_MOUNTED)
    5459         {
    5460             pIf->pDrvBlockBios->pfnSetTranslation(pIf->pDrvBlockBios, PDMBIOSTRANSLATION_NONE);
    5461             pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
    5462         }
     5416        pIf->PCHSGeometry.cCylinders = 0; /* dummy */
     5417        pIf->PCHSGeometry.cHeads     = 0; /* dummy */
     5418        pIf->PCHSGeometry.cSectors   = 0; /* dummy */
    54635419        LogRel(("PIIX3 ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
    54645420    }
     
    54665422    {
    54675423        pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 512;
    5468         rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
     5424        rc = pIf->pDrvBlockBios->pfnGetPCHSGeometry(pIf->pDrvBlockBios,
     5425                                                    &pIf->PCHSGeometry);
    54695426        if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
    54705427        {
    5471             pIf->cCHSCylinders = 0;
    5472             pIf->cCHSHeads     = 16; /*??*/
    5473             pIf->cCHSSectors   = 63; /*??*/
    5474         }
    5475         else if (VBOX_FAILURE(rc))
    5476         {
    5477             PDMBIOSTRANSLATION enmTranslation;
    5478             rc = pIf->pDrvBlockBios->pfnGetTranslation(pIf->pDrvBlockBios, &enmTranslation);
    5479             if (rc == VERR_PDM_TRANSLATION_NOT_SET)
    5480             {
    5481                 enmTranslation = PDMBIOSTRANSLATION_AUTO;
    5482                 pIf->cCHSCylinders = 0;
    5483                 rc = VINF_SUCCESS;
    5484             }
    5485             AssertRC(rc);
    5486 
    5487             if (    enmTranslation == PDMBIOSTRANSLATION_AUTO
    5488                 &&  (   pIf->cCHSCylinders == 0
    5489                      || pIf->cCHSHeads == 0
    5490                      || pIf->cCHSSectors == 0
    5491                     )
    5492                )
    5493             {
    5494                 /* Image contains no geometry information, detect geometry. */
    5495                 rc = ataGuessDiskLCHS(pIf, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
    5496                 if (VBOX_SUCCESS(rc))
    5497                 {
    5498                     /* Caution: the above function returns LCHS, but the
    5499                      * disk must report proper PCHS values for disks bigger
    5500                      * than approximately 512MB. */
    5501                     if (pIf->cCHSSectors == 63 && (pIf->cCHSHeads != 16 || pIf->cCHSCylinders >= 1024))
    5502                     {
    5503                         pIf->cCHSCylinders = pIf->cTotalSectors / 63 / 16;
    5504                         pIf->cCHSHeads = 16;
    5505                         pIf->cCHSSectors = 63;
    5506                         /* Set the disk CHS translation mode. */
    5507                          pIf->pDrvBlockBios->pfnSetTranslation(pIf->pDrvBlockBios, PDMBIOSTRANSLATION_LBA);
    5508                     }
    5509                     /* Set the disk geometry information. */
    5510                     rc = pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
    5511                 }
    5512                 else
    5513                 {
    5514                     /* Flag geometry as invalid, will be replaced below by the
    5515                      * default geometry. */
    5516                     pIf->cCHSCylinders = 0;
    5517                 }
    5518             }
    5519             if (!pIf->cCHSCylinders)
    5520             {
    5521                 /* If there is no geometry, use standard physical disk geometry.
    5522                  * This uses LCHS to LBA translation in the BIOS (which selects
    5523                  * the logical sector count 63 and the logical head count to be
    5524                  * the smallest of 16,32,64,128,255 which makes the logical
    5525                  * cylinder count smaller than 1024 - if that's not possible, it
    5526                  * uses 255 heads, so up to about 8 GByte maximum with the
    5527                  * standard int13 interface, which supports 1024 cylinders). */
    5528                 uint64_t cCHSCylinders = pIf->cTotalSectors / (16 * 63);
    5529                 pIf->cCHSCylinders = (uint32_t)RT_MAX(cCHSCylinders, 1);
    5530                 pIf->cCHSHeads = 16;
    5531                 pIf->cCHSSectors = 63;
    5532                 /* Set the disk geometry information. */
    5533                 rc = pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
    5534             }
    5535         }
    5536         else
    5537         {
    5538             PDMBIOSTRANSLATION enmTranslation;
    5539             rc = pIf->pDrvBlockBios->pfnGetTranslation(pIf->pDrvBlockBios, &enmTranslation);
    5540             if ((   rc == VERR_PDM_TRANSLATION_NOT_SET
    5541                  || enmTranslation == PDMBIOSTRANSLATION_LBA)
    5542                 &&  pIf->cCHSSectors == 63
    5543                 && (pIf->cCHSHeads != 16 || pIf->cCHSCylinders >= 1024))
    5544             {
    5545                 /* Use the official LBA physical CHS geometry. */
    5546                 uint64_t cCHSCylinders = pIf->cTotalSectors / (16 * 63);
    5547                 pIf->cCHSCylinders = RT_MAX((uint32_t)RT_MIN(cCHSCylinders, 16383), 1);
    5548                 pIf->cCHSHeads = 16;
    5549                 pIf->cCHSSectors = 63;
    5550                 /* DO NOT write back the disk geometry information. This
    5551                  * intentionally sets the ATA geometry only. */
    5552             }
    5553         }
    5554         LogRel(("PIIX3 ATA: LUN#%d: disk, CHS=%d/%d/%d, total number of sectors %Ld\n", pIf->iLUN, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors, pIf->cTotalSectors));
     5428            pIf->PCHSGeometry.cCylinders = 0;
     5429            pIf->PCHSGeometry.cHeads     = 16; /*??*/
     5430            pIf->PCHSGeometry.cSectors   = 63; /*??*/
     5431        }
     5432        else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
     5433        {
     5434            pIf->PCHSGeometry.cCylinders = 0; /* autodetect marker */
     5435            rc = VINF_SUCCESS;
     5436        }
     5437        AssertRC(rc);
     5438
     5439        if (   pIf->PCHSGeometry.cCylinders == 0
     5440            || pIf->PCHSGeometry.cHeads == 0
     5441            || pIf->PCHSGeometry.cSectors == 0
     5442           )
     5443        {
     5444            uint64_t cCylinders = pIf->cTotalSectors / (16 * 63);
     5445            pIf->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
     5446            pIf->PCHSGeometry.cHeads = 16;
     5447            pIf->PCHSGeometry.cSectors = 63;
     5448            /* Set the disk geometry information. */
     5449            rc = pIf->pDrvBlockBios->pfnSetPCHSGeometry(pIf->pDrvBlockBios,
     5450                                                        &pIf->PCHSGeometry);
     5451        }
     5452        LogRel(("PIIX3 ATA: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n", pIf->iLUN, pIf->PCHSGeometry.cCylinders, pIf->PCHSGeometry.cHeads, pIf->PCHSGeometry.cSectors, pIf->cTotalSectors));
    55555453    }
    55565454    return VINF_SUCCESS;
     
    57205618            SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fIrqPending);
    57215619            SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].cMultSectors);
    5722             SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSCylinders);
    5723             SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSHeads);
    5724             SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSSectors);
     5620            SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].PCHSGeometry.cCylinders);
     5621            SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].PCHSGeometry.cHeads);
     5622            SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].PCHSGeometry.cSectors);
    57255623            SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cSectorsPerIRQ);
    57265624            SSMR3PutU64(pSSMHandle, pData->aCts[i].aIfs[j].cTotalSectors);
     
    58255723            SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fIrqPending);
    58265724            SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].cMultSectors);
    5827             SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSCylinders);
    5828             SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSHeads);
    5829             SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSSectors);
     5725            SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].PCHSGeometry.cCylinders);
     5726            SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].PCHSGeometry.cHeads);
     5727            SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].PCHSGeometry.cSectors);
    58305728            SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cSectorsPerIRQ);
    58315729            SSMR3GetU64(pSSMHandle, &pData->aCts[i].aIfs[j].cTotalSectors);
  • trunk/src/VBox/Devices/Storage/DrvBlock.cpp

    r5999 r6291  
    7171    /** Visible to the BIOS. */
    7272    bool                    fBiosVisible;
    73     /** Whether or not enmTranslation is valid. */
    74     bool                    fTranslationSet;
    7573#ifdef VBOX_PERIODIC_FLUSH
    7674    /** HACK: Configuration value for number of bytes written after which to flush. */
     
    10098    RTUUID                  Uuid;
    10199
    102     /** BIOS Geometry: Translation mode. */
    103     PDMBIOSTRANSLATION      enmTranslation;
    104     /** BIOS Geometry: Cylinders. */
    105     uint32_t                cCylinders;
    106     /** BIOS Geometry: Heads. */
    107     uint32_t                cHeads;
    108     /** BIOS Geometry: Sectors. */
    109     uint32_t                cSectors;
     100    /** BIOS PCHS Geometry. */
     101    PDMMEDIAGEOMETRY        PCHSGeometry;
     102    /** BIOS LCHS Geometry. */
     103    PDMMEDIAGEOMETRY        LCHSGeometry;
    110104} DRVBLOCK, *PDRVBLOCK;
    111105
     
    254248
    255249
    256 /** @copydoc PDMIBLOCKBIOS::pfnGetGeometry */
    257 static DECLCALLBACK(int) drvblockGetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
     250/** @copydoc PDMIBLOCKBIOS::pfnGetPCHSGeometry */
     251static DECLCALLBACK(int) drvblockGetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
    258252{
    259253    PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
     
    268262     * Use configured/cached values if present.
    269263     */
    270     if (    pData->cCylinders > 0
    271         &&  pData->cHeads > 0
    272         &&  pData->cSectors > 0)
    273     {
    274         *pcCylinders = pData->cCylinders;
    275         *pcHeads     = pData->cHeads;
    276         *pcSectors   = pData->cSectors;
    277         LogFlow(("drvblockGetGeometry: returns VINF_SUCCESS {%d,%d,%d}\n", pData->cCylinders, pData->cHeads, pData->cSectors));
     264    if (    pData->PCHSGeometry.cCylinders > 0
     265        &&  pData->PCHSGeometry.cHeads > 0
     266        &&  pData->PCHSGeometry.cSectors > 0)
     267    {
     268        *pPCHSGeometry = pData->PCHSGeometry;
     269        LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pData->PCHSGeometry.cCylinders, pData->PCHSGeometry.cHeads, pData->PCHSGeometry.cSectors));
    278270        return VINF_SUCCESS;
    279271    }
     
    282274     * Call media.
    283275     */
    284     int rc = pData->pDrvMedia->pfnBiosGetGeometry(pData->pDrvMedia, pcCylinders, pcHeads, pcSectors);
     276    int rc = pData->pDrvMedia->pfnBiosGetPCHSGeometry(pData->pDrvMedia, &pData->PCHSGeometry);
    285277    if (VBOX_SUCCESS(rc))
    286278    {
    287         pData->cCylinders = *pcCylinders;
    288         pData->cHeads     = *pcHeads;
    289         pData->cSectors   = *pcSectors;
    290         LogFlow(("drvblockGetGeometry: returns %Vrc {%d,%d,%d}\n", rc, pData->cCylinders, pData->cHeads, pData->cSectors));
     279        *pPCHSGeometry = pData->PCHSGeometry;
     280        LogFlow(("%s: returns %Vrc {%d,%d,%d}\n", __FUNCTION__, rc, pData->PCHSGeometry.cCylinders, pData->PCHSGeometry.cHeads, pData->PCHSGeometry.cSectors));
    291281    }
    292282    else if (rc == VERR_NOT_IMPLEMENTED)
    293283    {
    294284        rc = VERR_PDM_GEOMETRY_NOT_SET;
    295         LogFlow(("drvblockGetGeometry: returns %Vrc\n", rc));
     285        LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    296286    }
    297287    return rc;
     
    299289
    300290
    301 /** @copydoc PDMIBLOCKBIOS::pfnSetGeometry */
    302 static DECLCALLBACK(int) drvblockSetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
    303 {
    304     LogFlow(("drvblockSetGeometry: cCylinders=%d cHeads=%d cSectors=%d\n", cCylinders, cHeads, cSectors));
     291/** @copydoc PDMIBLOCKBIOS::pfnSetPCHSGeometry */
     292static DECLCALLBACK(int) drvblockSetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
     293{
     294    LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
    305295    PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
    306296
     
    317307     * Call media. Ignore the not implemented return code.
    318308     */
    319     int rc = pData->pDrvMedia->pfnBiosSetGeometry(pData->pDrvMedia, cCylinders, cHeads, cSectors);
     309    int rc = pData->pDrvMedia->pfnBiosSetPCHSGeometry(pData->pDrvMedia, pPCHSGeometry);
    320310    if (    VBOX_SUCCESS(rc)
    321311        ||  rc == VERR_NOT_IMPLEMENTED)
    322312    {
    323         pData->cCylinders = cCylinders;
    324         pData->cHeads     = cHeads;
    325         pData->cSectors   = cSectors;
     313        pData->PCHSGeometry = *pPCHSGeometry;
    326314        rc = VINF_SUCCESS;
    327315    }
     
    330318
    331319
    332 /** @copydoc PDMIBLOCKBIOS::pfnGetTranslation */
    333 static DECLCALLBACK(int) drvblockGetTranslation(PPDMIBLOCKBIOS pInterface, PPDMBIOSTRANSLATION penmTranslation)
     320/** @copydoc PDMIBLOCKBIOS::pfnGetLCHSGeometry */
     321static DECLCALLBACK(int) drvblockGetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
    334322{
    335323    PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
     
    339327     */
    340328    if (!pData->pDrvMedia)
    341     {
    342         LogFlow(("drvblockGetTranslation: returns VERR_PDM_MEDIA_NOT_MOUNTED\n"));
    343329        return VERR_PDM_MEDIA_NOT_MOUNTED;
    344     }
    345 
    346     /*
    347      * Use configured/cached data if present.
    348      */
    349     if (pData->fTranslationSet)
    350     {
    351         *penmTranslation = pData->enmTranslation;
    352         LogFlow(("drvblockGetTranslation: returns VINF_SUCCESS *penmTranslation=%d\n", *penmTranslation));
     330
     331    /*
     332     * Use configured/cached values if present.
     333     */
     334    if (    pData->LCHSGeometry.cCylinders > 0
     335        &&  pData->LCHSGeometry.cHeads > 0
     336        &&  pData->LCHSGeometry.cSectors > 0)
     337    {
     338        *pLCHSGeometry = pData->LCHSGeometry;
     339        LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pData->LCHSGeometry.cCylinders, pData->LCHSGeometry.cHeads, pData->LCHSGeometry.cSectors));
    353340        return VINF_SUCCESS;
    354341    }
    355342
    356343    /*
    357      * Call media. Handle the not implemented status code.
    358      */
    359     int rc = pData->pDrvMedia->pfnBiosGetTranslation(pData->pDrvMedia, penmTranslation);
     344     * Call media.
     345     */
     346    int rc = pData->pDrvMedia->pfnBiosGetLCHSGeometry(pData->pDrvMedia, &pData->LCHSGeometry);
    360347    if (VBOX_SUCCESS(rc))
    361348    {
    362         pData->enmTranslation = *penmTranslation;
    363         pData->fTranslationSet = true;
     349        *pLCHSGeometry = pData->LCHSGeometry;
     350        LogFlow(("%s: returns %Vrc {%d,%d,%d}\n", __FUNCTION__, rc, pData->LCHSGeometry.cCylinders, pData->LCHSGeometry.cHeads, pData->LCHSGeometry.cSectors));
    364351    }
    365352    else if (rc == VERR_NOT_IMPLEMENTED)
    366         rc = VERR_PDM_TRANSLATION_NOT_SET;
    367     LogFlow(("drvblockGetTranslation: returns %Vrc *penmTranslation=%d\n", rc, *penmTranslation));
     353    {
     354        rc = VERR_PDM_GEOMETRY_NOT_SET;
     355        LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     356    }
    368357    return rc;
    369358}
    370359
    371360
    372 /** @copydoc PDMIBLOCKBIOS::pfnSetTranslation */
    373 static DECLCALLBACK(int) drvblockSetTranslation(PPDMIBLOCKBIOS pInterface, PDMBIOSTRANSLATION enmTranslation)
    374 {
    375     LogFlow(("drvblockSetTranslation: enmTranslation=%d\n", enmTranslation));
     361/** @copydoc PDMIBLOCKBIOS::pfnSetLCHSGeometry */
     362static DECLCALLBACK(int) drvblockSetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
     363{
     364    LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    376365    PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
    377366
     
    388377     * Call media. Ignore the not implemented return code.
    389378     */
    390     int rc = pData->pDrvMedia->pfnBiosSetTranslation(pData->pDrvMedia, enmTranslation);
     379    int rc = pData->pDrvMedia->pfnBiosSetLCHSGeometry(pData->pDrvMedia, pLCHSGeometry);
    391380    if (    VBOX_SUCCESS(rc)
    392381        ||  rc == VERR_NOT_IMPLEMENTED)
    393382    {
    394         pData->fTranslationSet = true;
    395         pData->enmTranslation = enmTranslation;
     383        pData->LCHSGeometry = *pLCHSGeometry;
    396384        rc = VINF_SUCCESS;
    397385    }
     
    471459         */
    472460        pData->fLocked = false;
    473         pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
    474         pData->cCylinders = pData->cHeads = pData->cSectors = 0;
     461        pData->PCHSGeometry.cCylinders  = 0;
     462        pData->PCHSGeometry.cHeads      = 0;
     463        pData->PCHSGeometry.cSectors    = 0;
     464        pData->LCHSGeometry.cCylinders  = 0;
     465        pData->LCHSGeometry.cHeads      = 0;
     466        pData->LCHSGeometry.cSectors    = 0;
    475467#ifdef VBOX_PERIODIC_FLUSH
    476468        pData->cbDataWritten = 0;
     
    627619     */
    628620#if defined(VBOX_PERIODIC_FLUSH) || defined(VBOX_IGNORE_FLUSH)
    629     if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Translation\0Mountable\0FlushInterval\0IgnoreFlush\0"))
     621    if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0FlushInterval\0IgnoreFlush\0"))
    630622#else /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
    631     if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Translation\0Mountable\0"))
     623    if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0"))
    632624#endif /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
    633625        return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
     
    651643
    652644    /* IBlockBios. */
    653     pData->IBlockBios.pfnGetGeometry        = drvblockGetGeometry;
    654     pData->IBlockBios.pfnSetGeometry        = drvblockSetGeometry;
    655     pData->IBlockBios.pfnGetTranslation     = drvblockGetTranslation;
    656     pData->IBlockBios.pfnSetTranslation     = drvblockSetTranslation;
     645    pData->IBlockBios.pfnGetPCHSGeometry    = drvblockGetPCHSGeometry;
     646    pData->IBlockBios.pfnSetPCHSGeometry    = drvblockSetPCHSGeometry;
     647    pData->IBlockBios.pfnGetLCHSGeometry    = drvblockGetLCHSGeometry;
     648    pData->IBlockBios.pfnSetLCHSGeometry    = drvblockSetLCHSGeometry;
    657649    pData->IBlockBios.pfnIsVisible          = drvblockIsVisible;
    658650    pData->IBlockBios.pfnGetType            = drvblockBiosGetType;
     
    746738
    747739    /* Cylinders */
    748     rc = CFGMR3QueryU32(pCfgHandle, "Cylinders", &pData->cCylinders);
     740    rc = CFGMR3QueryU32(pCfgHandle, "Cylinders", &pData->LCHSGeometry.cCylinders);
    749741    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    750         pData->cCylinders = 0;
     742        pData->LCHSGeometry.cCylinders = 0;
    751743    else if (VBOX_FAILURE(rc))
    752744    {
     
    756748
    757749    /* Heads */
    758     rc = CFGMR3QueryU32(pCfgHandle, "Heads", &pData->cHeads);
     750    rc = CFGMR3QueryU32(pCfgHandle, "Heads", &pData->LCHSGeometry.cHeads);
    759751    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    760         pData->cHeads = 0;
     752        pData->LCHSGeometry.cHeads = 0;
    761753    else if (VBOX_FAILURE(rc))
    762754    {
     
    766758
    767759    /* Sectors */
    768     rc = CFGMR3QueryU32(pCfgHandle, "Sectors", &pData->cSectors);
     760    rc = CFGMR3QueryU32(pCfgHandle, "Sectors", &pData->LCHSGeometry.cSectors);
    769761    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    770         pData->cSectors = 0;
     762        pData->LCHSGeometry.cSectors = 0;
    771763    else if (VBOX_FAILURE(rc))
    772764    {
    773765        AssertMsgFailed(("Configuration error: Query \"Sectors\" resulted in %Vrc.\n", rc));
    774766        return rc;
    775     }
    776 
    777     /* Translation */
    778     rc = CFGMR3QueryStringAlloc(pCfgHandle, "Translation", &psz);
    779     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    780     {
    781         pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
    782         pData->fTranslationSet = false;
    783     }
    784     else if (VBOX_SUCCESS(rc))
    785     {
    786         if (!strcmp(psz, "None"))
    787             pData->enmTranslation = PDMBIOSTRANSLATION_NONE;
    788         else if (!strcmp(psz, "LBA"))
    789             pData->enmTranslation = PDMBIOSTRANSLATION_LBA;
    790         else if (!strcmp(psz, "Auto"))
    791             pData->enmTranslation = PDMBIOSTRANSLATION_AUTO;
    792         else
    793         {
    794             AssertMsgFailed(("Configuration error: Unknown translation \"%s\".\n", psz));
    795             MMR3HeapFree(psz);
    796             return VERR_PDM_BLOCK_UNKNOWN_TRANSLATION;
    797         }
    798         MMR3HeapFree(psz); psz = NULL;
    799         pData->fTranslationSet = true;
    800     }
    801     else
    802     {
    803         AssertMsgFailed(("Configuration error: Failed to obtain the translation, rc=%Vrc.\n", rc));
    804         return VERR_PDM_BLOCK_NO_TYPE;
    805767    }
    806768
  • trunk/src/VBox/Devices/Storage/DrvHostBase.cpp

    r5999 r6291  
    321321
    322322
    323 /** @copydoc PDMIBLOCKBIOS::pfnGetGeometry */
    324 static DECLCALLBACK(int) drvHostBaseGetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
     323/** @copydoc PDMIBLOCKBIOS::pfnGetPCHSGeometry */
     324static DECLCALLBACK(int) drvHostBaseGetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
    325325{
    326326    PDRVHOSTBASE pThis =  PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
     
    330330    if (pThis->fMediaPresent)
    331331    {
    332         if (    pThis->cCylinders > 0
    333             &&  pThis->cHeads > 0
    334             &&  pThis->cSectors > 0)
    335         {
    336             *pcCylinders = pThis->cCylinders;
    337             *pcHeads = pThis->cHeads;
    338             *pcSectors = pThis->cSectors;
     332        if (    pThis->PCHSGeometry.cCylinders > 0
     333            &&  pThis->PCHSGeometry.cHeads > 0
     334            &&  pThis->PCHSGeometry.cSectors > 0)
     335        {
     336            *pPCHSGeometry = pThis->PCHSGeometry;
    339337        }
    340338        else
     
    345343
    346344    RTCritSectLeave(&pThis->CritSect);
    347     LogFlow(("%s-%d: drvHostBaseGetGeometry: returns %Vrc CHS={%d,%d,%d}\n",
    348              pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc, *pcCylinders, *pcHeads, *pcSectors));
     345    LogFlow(("%s-%d: %s: returns %Vrc CHS={%d,%d,%d}\n",
     346             pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, __FUNCTION__, rc, pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
    349347    return rc;
    350348}
    351349
    352350
    353 /** @copydoc PDMIBLOCKBIOS::pfnSetGeometry */
    354 static DECLCALLBACK(int) drvHostBaseSetGeometry(PPDMIBLOCKBIOS pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
     351/** @copydoc PDMIBLOCKBIOS::pfnSetPCHSGeometry */
     352static DECLCALLBACK(int) drvHostBaseSetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
    355353{
    356354    PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
    357     LogFlow(("%s-%d: drvHostBaseSetGeometry: cCylinders=%d cHeads=%d cSectors=%d\n",
    358              pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, cCylinders, cHeads, cSectors));
     355    LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
     356             pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
    359357    RTCritSectEnter(&pThis->CritSect);
    360358
     
    362360    if (pThis->fMediaPresent)
    363361    {
    364         pThis->cCylinders = cCylinders;
    365         pThis->cHeads     = cHeads;
    366         pThis->cSectors   = cSectors;
     362        pThis->PCHSGeometry = *pPCHSGeometry;
    367363    }
    368364    else
     
    377373
    378374
    379 /** @copydoc PDMIBLOCKBIOS::pfnGetTranslation */
    380 static DECLCALLBACK(int) drvHostBaseGetTranslation(PPDMIBLOCKBIOS pInterface, PPDMBIOSTRANSLATION penmTranslation)
    381 {
    382     PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
     375/** @copydoc PDMIBLOCKBIOS::pfnGetLCHSGeometry */
     376static DECLCALLBACK(int) drvHostBaseGetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
     377{
     378    PDRVHOSTBASE pThis =  PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
    383379    RTCritSectEnter(&pThis->CritSect);
    384380
     
    386382    if (pThis->fMediaPresent)
    387383    {
    388         if (pThis->fTranslationSet)
    389             *penmTranslation = pThis->enmTranslation;
     384        if (    pThis->LCHSGeometry.cCylinders > 0
     385            &&  pThis->LCHSGeometry.cHeads > 0
     386            &&  pThis->LCHSGeometry.cSectors > 0)
     387        {
     388            *pLCHSGeometry = pThis->LCHSGeometry;
     389        }
    390390        else
    391             rc = VERR_PDM_TRANSLATION_NOT_SET;
     391            rc = VERR_PDM_GEOMETRY_NOT_SET;
    392392    }
    393393    else
     
    395395
    396396    RTCritSectLeave(&pThis->CritSect);
    397     LogFlow(("%s-%d: drvHostBaseGetTranslation: returns %Vrc *penmTranslation=%d\n",
    398              pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, rc, *penmTranslation));
     397    LogFlow(("%s-%d: %s: returns %Vrc CHS={%d,%d,%d}\n",
     398             pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, __FUNCTION__, rc, pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
    399399    return rc;
    400400}
    401401
    402402
    403 /** @copydoc PDMIBLOCKBIOS::pfnSetTranslation */
    404 static DECLCALLBACK(int) drvHostBaseSetTranslation(PPDMIBLOCKBIOS pInterface, PDMBIOSTRANSLATION enmTranslation)
     403/** @copydoc PDMIBLOCKBIOS::pfnSetLCHSGeometry */
     404static DECLCALLBACK(int) drvHostBaseSetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
    405405{
    406406    PDRVHOSTBASE pThis = PDMIBLOCKBIOS_2_DRVHOSTBASE(pInterface);
    407     LogFlow(("%s-%d: drvHostBaseSetTranslation: enmTranslation=%d\n",
    408              pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, enmTranslation));
     407    LogFlow(("%s-%d: %s: cCylinders=%d cHeads=%d cSectors=%d\n",
     408             pThis->pDrvIns->pDrvReg->szDriverName, pThis->pDrvIns->iInstance, __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    409409    RTCritSectEnter(&pThis->CritSect);
    410410
     
    412412    if (pThis->fMediaPresent)
    413413    {
    414         pThis->fTranslationSet = true;
    415         pThis->enmTranslation = enmTranslation;
     414        pThis->LCHSGeometry = *pLCHSGeometry;
    416415    }
    417416    else
     
    12771276    pThis->fMediaPresent = false;
    12781277    pThis->fLocked = false;
    1279     pThis->fTranslationSet = false;
    1280     pThis->cSectors = 0;
     1278    pThis->PCHSGeometry.cCylinders = 0;
     1279    pThis->PCHSGeometry.cHeads = 0;
     1280    pThis->PCHSGeometry.cSectors = 0;
     1281    pThis->LCHSGeometry.cCylinders = 0;
     1282    pThis->LCHSGeometry.cHeads = 0;
     1283    pThis->LCHSGeometry.cSectors = 0;
    12811284    if (pThis->pDrvMountNotify)
    12821285        pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
     
    17011704
    17021705    /* IBlockBios. */
    1703     pThis->IBlockBios.pfnGetGeometry        = drvHostBaseGetGeometry;
    1704     pThis->IBlockBios.pfnSetGeometry        = drvHostBaseSetGeometry;
    1705     pThis->IBlockBios.pfnGetTranslation     = drvHostBaseGetTranslation;
    1706     pThis->IBlockBios.pfnSetTranslation     = drvHostBaseSetTranslation;
     1706    pThis->IBlockBios.pfnGetPCHSGeometry    = drvHostBaseGetPCHSGeometry;
     1707    pThis->IBlockBios.pfnSetPCHSGeometry    = drvHostBaseSetPCHSGeometry;
     1708    pThis->IBlockBios.pfnGetLCHSGeometry    = drvHostBaseGetLCHSGeometry;
     1709    pThis->IBlockBios.pfnSetLCHSGeometry    = drvHostBaseSetLCHSGeometry;
    17071710    pThis->IBlockBios.pfnIsVisible          = drvHostBaseIsVisible;
    17081711    pThis->IBlockBios.pfnGetType            = drvHostBaseBiosGetType;
  • trunk/src/VBox/Devices/Storage/DrvHostBase.h

    r5999 r6291  
    9797    bool volatile           fShutdownPoller;
    9898
    99     /** Whether or not enmTranslation is valid. */
    100     bool                    fTranslationSet;
    101     /** BIOS Geometry: Translation mode. */
    102     PDMBIOSTRANSLATION      enmTranslation;
    103     /** BIOS Geometry: Cylinders. */
    104     uint32_t                cCylinders;
    105     /** BIOS Geometry: Heads. */
    106     uint32_t                cHeads;
    107     /** BIOS Geometry: Sectors. */
    108     uint32_t                cSectors;
     99    /** BIOS PCHS geometry. */
     100    PDMMEDIAGEOMETRY        PCHSGeometry;
     101    /** BIOS LCHS geometry. */
     102    PDMMEDIAGEOMETRY        LCHSGeometry;
    109103
    110104    /** The number of errors that could go into the release log. (flood gate) */
  • trunk/src/VBox/Devices/Storage/DrvMediaISO.cpp

    r5999 r6291  
    7373static DECLCALLBACK(uint64_t) drvMediaISOGetSize(PPDMIMEDIA pInterface);
    7474static DECLCALLBACK(int) drvMediaISOGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid);
    75 static DECLCALLBACK(int) drvMediaISOBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors);
    76 static DECLCALLBACK(int) drvMediaISOBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors);
    77 static DECLCALLBACK(int) drvMediaISOBiosGetTranslation(PPDMIMEDIA pInterface, PPDMBIOSTRANSLATION penmTranslation);
    78 static DECLCALLBACK(int) drvMediaISOBiosSetTranslation(PPDMIMEDIA pInterface, PDMBIOSTRANSLATION enmTranslation);
     75static DECLCALLBACK(int) drvMediaISOBiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry);
     76static DECLCALLBACK(int) drvMediaISOBiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry);
     77static DECLCALLBACK(int) drvMediaISOBiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry);
     78static DECLCALLBACK(int) drvMediaISOBiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry);
    7979
    8080static DECLCALLBACK(void *) drvMediaISOQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface);
     
    111111    pData->IMedia.pfnGetUuid            = drvMediaISOGetUuid;
    112112    pData->IMedia.pfnIsReadOnly         = drvMediaISOIsReadOnly;
    113     pData->IMedia.pfnBiosGetGeometry    = drvMediaISOBiosGetGeometry;
    114     pData->IMedia.pfnBiosSetGeometry    = drvMediaISOBiosSetGeometry;
    115     pData->IMedia.pfnBiosGetTranslation = drvMediaISOBiosGetTranslation;
    116     pData->IMedia.pfnBiosSetTranslation = drvMediaISOBiosSetTranslation;
     113    pData->IMedia.pfnBiosGetPCHSGeometry = drvMediaISOBiosGetPCHSGeometry;
     114    pData->IMedia.pfnBiosSetPCHSGeometry = drvMediaISOBiosSetPCHSGeometry;
     115    pData->IMedia.pfnBiosGetLCHSGeometry = drvMediaISOBiosGetLCHSGeometry;
     116    pData->IMedia.pfnBiosSetLCHSGeometry = drvMediaISOBiosSetLCHSGeometry;
    117117
    118118    /*
     
    192192
    193193
    194 /** @copydoc PDMIMEDIA::pfnBiosGetGeometry */
    195 static DECLCALLBACK(int) drvMediaISOBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
    196 {
    197     return VERR_NOT_IMPLEMENTED;
    198 }
    199 
    200 
    201 /** @copydoc PDMIMEDIA::pfnBiosSetGeometry */
    202 static DECLCALLBACK(int) drvMediaISOBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
     194/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
     195static DECLCALLBACK(int) drvMediaISOBiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
     196{
     197    return VERR_NOT_IMPLEMENTED;
     198}
     199
     200
     201/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
     202static DECLCALLBACK(int) drvMediaISOBiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
     203{
     204    return VERR_NOT_IMPLEMENTED;
     205}
     206
     207
     208/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
     209static DECLCALLBACK(int) drvMediaISOBiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
     210{
     211    return VERR_NOT_IMPLEMENTED;
     212}
     213
     214
     215/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
     216static DECLCALLBACK(int) drvMediaISOBiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
    203217{
    204218    return VERR_NOT_IMPLEMENTED;
     
    272286{
    273287    return true;
    274 }
    275 
    276 
    277 /**
    278  * Stub - operation not supported.
    279  *
    280  * @copydoc PDMIMEDIA::pfnBiosGetTranslation
    281  */
    282 static DECLCALLBACK(int) drvMediaISOBiosGetTranslation(PPDMIMEDIA pInterface, PPDMBIOSTRANSLATION penmTranslation)
    283 {
    284     NOREF(pInterface); NOREF(penmTranslation);
    285     return VERR_NOT_IMPLEMENTED;
    286 }
    287 
    288 
    289 /**
    290  * Stub - operation not supported.
    291  *
    292  * @copydoc PDMIMEDIA::pfnBiosSetTranslation
    293  */
    294 static DECLCALLBACK(int) drvMediaISOBiosSetTranslation(PPDMIMEDIA pInterface, PDMBIOSTRANSLATION enmTranslation)
    295 {
    296     NOREF(pInterface); NOREF(enmTranslation);
    297     return VERR_NOT_IMPLEMENTED;
    298288}
    299289
  • trunk/src/VBox/Devices/Storage/DrvRawImage.cpp

    r6198 r6291  
    7676static DECLCALLBACK(uint64_t) drvRawImageGetSize(PPDMIMEDIA pInterface);
    7777static DECLCALLBACK(int) drvRawImageGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid);
    78 static DECLCALLBACK(int) drvRawImageBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors);
    79 static DECLCALLBACK(int) drvRawImageBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors);
    80 static DECLCALLBACK(int) drvRawImageBiosGetTranslation(PPDMIMEDIA pInterface, PPDMBIOSTRANSLATION penmTranslation);
    81 static DECLCALLBACK(int) drvRawImageBiosSetTranslation(PPDMIMEDIA pInterface, PDMBIOSTRANSLATION enmTranslation);
     78static DECLCALLBACK(int) drvRawImageBiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry);
     79static DECLCALLBACK(int) drvRawImageBiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry);
     80static DECLCALLBACK(int) drvRawImageBiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry);
     81static DECLCALLBACK(int) drvRawImageBiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry);
    8282
    8383static DECLCALLBACK(void *) drvRawImageQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface);
     
    114114    pData->IMedia.pfnGetUuid            = drvRawImageGetUuid;
    115115    pData->IMedia.pfnIsReadOnly         = drvRawImageIsReadOnly;
    116     pData->IMedia.pfnBiosGetGeometry    = drvRawImageBiosGetGeometry;
    117     pData->IMedia.pfnBiosSetGeometry    = drvRawImageBiosSetGeometry;
    118     pData->IMedia.pfnBiosGetTranslation = drvRawImageBiosGetTranslation;
    119     pData->IMedia.pfnBiosSetTranslation = drvRawImageBiosSetTranslation;
     116    pData->IMedia.pfnBiosGetPCHSGeometry = drvRawImageBiosGetPCHSGeometry;
     117    pData->IMedia.pfnBiosSetPCHSGeometry = drvRawImageBiosSetPCHSGeometry;
     118    pData->IMedia.pfnBiosGetLCHSGeometry = drvRawImageBiosGetLCHSGeometry;
     119    pData->IMedia.pfnBiosSetLCHSGeometry = drvRawImageBiosSetLCHSGeometry;
    120120
    121121    /*
     
    207207
    208208
    209 /** @copydoc PDMIMEDIA::pfnBiosGetGeometry */
    210 static DECLCALLBACK(int) drvRawImageBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
     209/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
     210static DECLCALLBACK(int) drvRawImageBiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
    211211{
    212212    return VERR_NOT_IMPLEMENTED;
     
    214214
    215215
    216 /** @copydoc PDMIMEDIA::pfnBiosSetGeometry */
    217 static DECLCALLBACK(int) drvRawImageBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
     216/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
     217static DECLCALLBACK(int) drvRawImageBiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
     218{
     219    return VERR_NOT_IMPLEMENTED;
     220}
     221
     222
     223/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
     224static DECLCALLBACK(int) drvRawImageBiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
     225{
     226    return VERR_NOT_IMPLEMENTED;
     227}
     228
     229
     230/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
     231static DECLCALLBACK(int) drvRawImageBiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
    218232{
    219233    return VERR_NOT_IMPLEMENTED;
     
    319333    PDRVRAWIMAGE pData = PDMIMEDIA_2_DRVRAWIMAGE(pInterface);
    320334    return pData->fReadOnly;
    321 }
    322 
    323 
    324 /**
    325  * Stub - operation not supported.
    326  *
    327  * @copydoc PDMIMEDIA::pfnBiosGetTranslation
    328  */
    329 static DECLCALLBACK(int) drvRawImageBiosGetTranslation(PPDMIMEDIA pInterface, PPDMBIOSTRANSLATION penmTranslation)
    330 {
    331     NOREF(pInterface); NOREF(penmTranslation);
    332     return VERR_NOT_IMPLEMENTED;
    333 }
    334 
    335 
    336 /**
    337  * Stub - operation not supported.
    338  *
    339  * @copydoc PDMIMEDIA::pfnBiosSetTranslation
    340  */
    341 static DECLCALLBACK(int) drvRawImageBiosSetTranslation(PPDMIMEDIA pInterface, PDMBIOSTRANSLATION enmTranslation)
    342 {
    343     NOREF(pInterface); NOREF(enmTranslation);
    344     return VERR_NOT_IMPLEMENTED;
    345335}
    346336
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r5999 r6291  
    77
    88/*
    9  * Copyright (C) 2006-2007 innotek GmbH
     9 * Copyright (C) 2006-2008 innotek GmbH
    1010 *
    1111 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    7272*******************************************************************************/
    7373
    74 static void vdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
     74static void drvvdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL,
     75                               const char *pszFormat, va_list va)
    7576{
    7677    PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser;
     
    8384
    8485/** @copydoc PDMIMEDIA::pfnRead */
    85 static DECLCALLBACK(int) vdRead(PPDMIMEDIA pInterface,
    86                                 uint64_t off, void *pvBuf, size_t cbRead)
     86static DECLCALLBACK(int) drvvdRead(PPDMIMEDIA pInterface,
     87                                   uint64_t off, void *pvBuf, size_t cbRead)
    8788{
    8889    LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__,
     
    9899
    99100/** @copydoc PDMIMEDIA::pfnWrite */
    100 static DECLCALLBACK(int) vdWrite(PPDMIMEDIA pInterface,
    101                                  uint64_t off, const void *pvBuf,
    102                                  size_t cbWrite)
     101static DECLCALLBACK(int) drvvdWrite(PPDMIMEDIA pInterface,
     102                                    uint64_t off, const void *pvBuf,
     103                                    size_t cbWrite)
    103104{
    104105    LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__,
     
    113114
    114115/** @copydoc PDMIMEDIA::pfnFlush */
    115 static DECLCALLBACK(int) vdFlush(PPDMIMEDIA pInterface)
     116static DECLCALLBACK(int) drvvdFlush(PPDMIMEDIA pInterface)
    116117{
    117118    LogFlow(("%s:\n", __FUNCTION__));
     
    123124
    124125/** @copydoc PDMIMEDIA::pfnGetSize */
    125 static DECLCALLBACK(uint64_t) vdGetSize(PPDMIMEDIA pInterface)
    126 {
    127     LogFlow(("%s:\n", __FUNCTION__));
    128     PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
    129     uint64_t cb = VDGetSize(pData->pDisk);
     126static DECLCALLBACK(uint64_t) drvvdGetSize(PPDMIMEDIA pInterface)
     127{
     128    LogFlow(("%s:\n", __FUNCTION__));
     129    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
     130    uint64_t cb = VDGetSize(pData->pDisk, VD_LAST_IMAGE);
    130131    LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb));
    131132    return cb;
     
    133134
    134135/** @copydoc PDMIMEDIA::pfnIsReadOnly */
    135 static DECLCALLBACK(bool) vdIsReadOnly(PPDMIMEDIA pInterface)
     136static DECLCALLBACK(bool) drvvdIsReadOnly(PPDMIMEDIA pInterface)
    136137{
    137138    LogFlow(("%s:\n", __FUNCTION__));
     
    142143}
    143144
    144 /** @copydoc PDMIMEDIA::pfnBiosGetGeometry */
    145 static DECLCALLBACK(int) vdBiosGetGeometry(PPDMIMEDIA pInterface,
    146                                            uint32_t *pcCylinders,
    147                                            uint32_t *pcHeads,
    148                                            uint32_t *pcSectors)
    149 {
    150     LogFlow(("%s:\n", __FUNCTION__));
    151     PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
    152     int rc = VDGetGeometry(pData->pDisk, pcCylinders, pcHeads, pcSectors);
     145/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
     146static DECLCALLBACK(int) drvvdBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
     147                                                  PPDMMEDIAGEOMETRY pPCHSGeometry)
     148{
     149    LogFlow(("%s:\n", __FUNCTION__));
     150    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
     151    int rc = VDGetPCHSGeometry(pData->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
    153152    if (VBOX_FAILURE(rc))
    154153    {
     
    157156    }
    158157    LogFlow(("%s: returns %Vrc (CHS=%d/%d/%d)\n", __FUNCTION__,
    159              rc, *pcCylinders, *pcHeads, *pcSectors));
    160     return rc;
    161 }
    162 
    163 /** @copydoc PDMIMEDIA::pfnBiosSetGeometry */
    164 static DECLCALLBACK(int) vdBiosSetGeometry(PPDMIMEDIA pInterface,
    165                                            uint32_t cCylinders,
    166                                            uint32_t cHeads,
    167                                            uint32_t cSectors)
     158             rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
     159    return rc;
     160}
     161
     162/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
     163static DECLCALLBACK(int) drvvdBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
     164                                                  PCPDMMEDIAGEOMETRY pPCHSGeometry)
    168165{
    169166    LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
    170              cCylinders, cHeads, cSectors));
    171     PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
    172     int rc = VDSetGeometry(pData->pDisk, cCylinders, cHeads, cSectors);
     167             pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
     168    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
     169    int rc = VDSetPCHSGeometry(pData->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
    173170    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    174171    return rc;
    175172}
    176173
    177 /** @copydoc PDMIMEDIA::pfnBiosGetTranslation */
    178 static DECLCALLBACK(int) vdBiosGetTranslation(PPDMIMEDIA pInterface,
    179                                               PPDMBIOSTRANSLATION penmTranslation)
    180 {
    181     LogFlow(("%s:\n", __FUNCTION__));
    182     PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
    183     int rc = VDGetTranslation(pData->pDisk, penmTranslation);
    184     LogFlow(("%s: returns %Vrc (%d)\n", __FUNCTION__, rc, *penmTranslation));
    185     return rc;
    186 }
    187 
    188 /** @copydoc PDMIMEDIA::pfnBiosSetTranslation */
    189 static DECLCALLBACK(int) vdBiosSetTranslation(PPDMIMEDIA pInterface,
    190                                               PDMBIOSTRANSLATION enmTranslation)
    191 {
    192     LogFlow(("%s:\n", __FUNCTION__));
    193     PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
    194     int rc = VDSetTranslation(pData->pDisk, enmTranslation);
    195     LogFlow(("%s: returns %Vrc (%d)\n", __FUNCTION__, rc, enmTranslation));
     174/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
     175static DECLCALLBACK(int) drvvdBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
     176                                                  PPDMMEDIAGEOMETRY pLCHSGeometry)
     177{
     178    LogFlow(("%s:\n", __FUNCTION__));
     179    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
     180    int rc = VDGetLCHSGeometry(pData->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
     181    if (VBOX_FAILURE(rc))
     182    {
     183        Log(("%s: geometry not available.\n", __FUNCTION__));
     184        rc = VERR_PDM_GEOMETRY_NOT_SET;
     185    }
     186    LogFlow(("%s: returns %Vrc (CHS=%d/%d/%d)\n", __FUNCTION__,
     187             rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
     188    return rc;
     189}
     190
     191/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
     192static DECLCALLBACK(int) drvvdBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
     193                                                  PCPDMMEDIAGEOMETRY pLCHSGeometry)
     194{
     195    LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
     196             pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
     197    PVBOXDISK pData = PDMIMEDIA_2_VBOXDISK(pInterface);
     198    int rc = VDSetLCHSGeometry(pData->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
     199    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    196200    return rc;
    197201}
    198202
    199203/** @copydoc PDMIMEDIA::pfnGetUuid */
    200 static DECLCALLBACK(int) vdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
     204static DECLCALLBACK(int) drvvdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
    201205{
    202206    LogFlow(("%s:\n", __FUNCTION__));
     
    213217
    214218/** @copydoc PDMIBASE::pfnQueryInterface */
    215 static DECLCALLBACK(void *) vdQueryInterface(PPDMIBASE pInterface,
    216                                              PDMINTERFACE enmInterface)
     219static DECLCALLBACK(void *) drvvdQueryInterface(PPDMIBASE pInterface,
     220                                                PDMINTERFACE enmInterface)
    217221{
    218222    PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
     
    245249 *                      to be used frequently in this function.
    246250 */
    247 static DECLCALLBACK(int) vdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
     251static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
     252                                        PCFGMNODE pCfgHandle)
    248253{
    249254    LogFlow(("%s:\n", __FUNCTION__));
     
    257262     * Init the static parts.
    258263     */
    259     pDrvIns->IBase.pfnQueryInterface    = vdQueryInterface;
     264    pDrvIns->IBase.pfnQueryInterface    = drvvdQueryInterface;
    260265    pData->pDrvIns = pDrvIns;
    261266    pData->fTempReadOnly = false;
    262267
    263268    /* IMedia */
    264     pData->IMedia.pfnRead               = vdRead;
    265     pData->IMedia.pfnWrite              = vdWrite;
    266     pData->IMedia.pfnFlush              = vdFlush;
    267     pData->IMedia.pfnGetSize            = vdGetSize;
    268     pData->IMedia.pfnIsReadOnly         = vdIsReadOnly;
    269     pData->IMedia.pfnBiosGetGeometry    = vdBiosGetGeometry;
    270     pData->IMedia.pfnBiosSetGeometry    = vdBiosSetGeometry;
    271     pData->IMedia.pfnBiosGetTranslation = vdBiosGetTranslation;
    272     pData->IMedia.pfnBiosSetTranslation = vdBiosSetTranslation;
    273     pData->IMedia.pfnGetUuid            = vdGetUuid;
     269    pData->IMedia.pfnRead               = drvvdRead;
     270    pData->IMedia.pfnWrite              = drvvdWrite;
     271    pData->IMedia.pfnFlush              = drvvdFlush;
     272    pData->IMedia.pfnGetSize            = drvvdGetSize;
     273    pData->IMedia.pfnIsReadOnly         = drvvdIsReadOnly;
     274    pData->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
     275    pData->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
     276    pData->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
     277    pData->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
     278    pData->IMedia.pfnGetUuid            = drvvdGetUuid;
    274279
    275280    /*
     
    326331        if (VBOX_SUCCESS(rc))
    327332        {
    328             rc = VDCreate(pData->szFormat, vdErrorCallback, pDrvIns, &pData->pDisk);
     333            rc = VDCreate(pData->szFormat, drvvdErrorCallback, pDrvIns, &pData->pDisk);
    329334            /* Error message is already set correctly. */
    330335        }
     
    420425 * @param   pDrvIns     The driver instance data.
    421426 */
    422 static DECLCALLBACK(void) vdDestruct(PPDMDRVINS pDrvIns)
     427static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
    423428{
    424429    LogFlow(("%s:\n", __FUNCTION__));
     
    436441 * @param   pDrvIns     The driver instance data.
    437442 */
    438 static DECLCALLBACK(void) vdSuspend(PPDMDRVINS pDrvIns)
     443static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
    439444{
    440445    LogFlow(("%s:\n", __FUNCTION__));
     
    443448    {
    444449        unsigned uOpenFlags;
    445         int rc = VDGetOpenFlags(pData->pDisk, &uOpenFlags);
     450        int rc = VDGetOpenFlags(pData->pDisk, VD_LAST_IMAGE, &uOpenFlags);
    446451        AssertRC(rc);
    447452        uOpenFlags |= VD_OPEN_FLAGS_READONLY;
    448         rc = VDSetOpenFlags(pData->pDisk, uOpenFlags);
     453        rc = VDSetOpenFlags(pData->pDisk, VD_LAST_IMAGE, uOpenFlags);
    449454        AssertRC(rc);
    450455        pData->fTempReadOnly = true;
     
    454459/**
    455460 * Before the VM resumes we'll have to undo the read-only mode change
    456  * done in vdSuspend.
     461 * done in drvvdSuspend.
    457462 *
    458463 * @param   pDrvIns     The driver instance data.
    459464 */
    460 static DECLCALLBACK(void) vdResume(PPDMDRVINS pDrvIns)
     465static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
    461466{
    462467    LogFlow(("%s:\n", __FUNCTION__));
     
    465470    {
    466471        unsigned uOpenFlags;
    467         int rc = VDGetOpenFlags(pData->pDisk, &uOpenFlags);
     472        int rc = VDGetOpenFlags(pData->pDisk, VD_LAST_IMAGE, &uOpenFlags);
    468473        AssertRC(rc);
    469474        uOpenFlags &= ~VD_OPEN_FLAGS_READONLY;
    470         rc = VDSetOpenFlags(pData->pDisk, uOpenFlags);
     475        rc = VDSetOpenFlags(pData->pDisk, VD_LAST_IMAGE, uOpenFlags);
    471476        AssertRC(rc);
    472477        pData->fTempReadOnly = false;
     
    484489    PDM_DRVREG_VERSION,
    485490    /* szDriverName */
    486     "VD",
     491    "DrvVD",
    487492    /* pszDescription */
    488493    "Generic VBox disk media driver.",
     
    496501    sizeof(VBOXDISK),
    497502    /* pfnConstruct */
    498     vdConstruct,
     503    drvvdConstruct,
    499504    /* pfnDestruct */
    500     vdDestruct,
     505    drvvdDestruct,
    501506    /* pfnIOCtl */
    502507    NULL,
     
    506511    NULL,
    507512    /* pfnSuspend */
    508     vdSuspend,
     513    drvvdSuspend,
    509514    /* pfnResume */
    510     vdResume,
     515    drvvdResume,
    511516    /* pfnDetach */
    512517    NULL
  • trunk/src/VBox/Devices/Storage/VBoxHDD-new.cpp

    • Property svn:eol-style set to native
    • Property svn:keywords set to Author Date Id Revision
    r6204 r6291  
    55
    66/*
    7  * Copyright (C) 2006-2007 innotek GmbH
     7 * Copyright (C) 2006-2008 innotek GmbH
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3333#include <iprt/dir.h>
    3434#include <iprt/path.h>
     35#include <iprt/param.h>
    3536
    3637#include "VBoxHDD-newInternal.h"
     
    3940#define VBOXHDDDISK_SIGNATURE 0x6f0e2a7d
    4041
     42/** Buffer size used for merging images. */
     43#define VD_MERGE_BUFFER_SIZE    (1024 * 1024)
    4144
    4245/**
     
    8992    /** Cached size of this disk. */
    9093    uint64_t            cbSize;
    91     /** Cached CHS geometry for this disk, cylinders. */
    92     unsigned            cCylinders;
    93     /** Cached CHS geometry for this disk, heads. */
    94     unsigned            cHeads;
    95     /** Cached CHS geometry for this disk, sectors. */
    96     unsigned            cSectors;
    97     /** Cached translation mode for this disk. */
    98     PDMBIOSTRANSLATION  enmTranslation;
     94    /** Cached PCHS geometry for this disk. */
     95    PDMMEDIAGEOMETRY    PCHSGeometry;
     96    /** Cached LCHS geometry for this disk. */
     97    PDMMEDIAGEOMETRY    LCHSGeometry;
    9998
    10099    /** Error message processing callback. */
     
    106105    RTLDRMOD            hPlugin;
    107106    /** Function pointers for the various backend methods. */
    108     PVBOXHDDBACKEND     Backend;
     107    PCVBOXHDDBACKEND    Backend;
    109108};
    110 
    111 
    112 typedef struct
    113 {
    114     const char          *pszBackendName;
    115     PVBOXHDDBACKEND     Backend;
    116 } VBOXHDDBACKENDENTRY;
    117109
    118110
     
    122114#endif
    123115
    124 static const VBOXHDDBACKENDENTRY aBackends[] =
    125 {
    126     { "VMDK", &g_VmdkBackend },
    127 #ifndef VBOX_OSE
    128     { "VHD",  &g_VhdBackend},
    129 #endif
    130     { NULL, NULL }
     116static PCVBOXHDDBACKEND aBackends[] =
     117{
     118    { &g_VmdkBackend },
     119    { &g_VhdBackend},
     120    { NULL }
    131121};
    132122
     
    214204{
    215205    PVDIMAGE pImage = pDisk->pBase;
     206    if (nImage == VD_LAST_IMAGE)
     207        return pDisk->pLast;
    216208    while (pImage && nImage)
    217209    {
     
    231223    int rc;
    232224    size_t cbThisRead;
    233     PVDIMAGE pCurrImage;
    234225
    235226    /* Loop until all read. */
     
    241232        cbThisRead = cbRead;
    242233        rc = VINF_VDI_BLOCK_FREE;
    243         for (pCurrImage = pImage;
     234        for (PVDIMAGE pCurrImage = pImage;
    244235             pCurrImage != NULL && rc == VINF_VDI_BLOCK_FREE;
    245236             pCurrImage = pCurrImage->pPrev)
     
    320311    if (cbPreRead)
    321312    {
    322         rc = vdReadHelper(pDisk, pImage->pPrev, uOffset - cbPreRead,
    323                           pvTmp, cbPreRead);
     313        rc = vdReadHelper(pDisk, pImage->pPrev, uOffset - cbPreRead, pvTmp,
     314                          cbPreRead);
    324315        if (VBOX_FAILURE(rc))
    325316            return rc;
     
    417408    /* Read the entire data of the block so that we can compare whether it will
    418409     * be modified by the write or not. */
    419     rc = vdReadHelper(pDisk, pImage->pPrev, uOffset - cbPreRead,
    420                       pvTmp, cbPreRead + cbThisWrite + cbPostRead - cbFill);
     410    rc = vdReadHelper(pDisk, pImage->pPrev, uOffset - cbPreRead, pvTmp,
     411                      cbPreRead + cbThisWrite + cbPostRead - cbFill);
    421412    if (VBOX_FAILURE(rc))
    422413        return rc;
     
    462453
    463454/**
    464  * Allocates and initializes an empty VBox HDD container.
     455 * internal: write buffer to the image, taking care of block boundaries and
     456 * write optimizations.
     457 */
     458static int vdWriteHelper(PVBOXHDD pDisk, PVDIMAGE pImage, uint64_t uOffset,
     459                         const void *pvBuf, size_t cbWrite)
     460{
     461    int rc;
     462    size_t cbThisWrite;
     463    size_t cbPreRead, cbPostRead;
     464
     465    /* Loop until all written. */
     466    do
     467    {
     468        /* Try to write the possibly partial block to the last opened image.
     469         * This works when the block is already allocated in this image or
     470         * if it is a full-block write, which automatically allocates a new
     471         * block if needed. */
     472        cbThisWrite = cbWrite;
     473        rc = pDisk->Backend->pfnWrite(pImage->pvBackendData, uOffset, pvBuf,
     474                                      cbThisWrite, &cbThisWrite, &cbPreRead,
     475                                      &cbPostRead);
     476        if (rc == VINF_VDI_BLOCK_FREE)
     477        {
     478            void *pvTmp = RTMemTmpAlloc(cbPreRead + cbThisWrite + cbPostRead);
     479            AssertBreak(!pvTmp, rc = VERR_NO_MEMORY);
     480
     481            if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME))
     482            {
     483                /* Optimized write, suppress writing to a so far unallocated
     484                 * block if the data is in fact not changed. */
     485                rc = vdWriteHelperOptimized(pDisk, pImage, uOffset, cbWrite,
     486                                            cbThisWrite, cbPreRead, cbPostRead,
     487                                            pvBuf, pvTmp);
     488            }
     489            else
     490            {
     491                /* Normal write, not optimized in any way. The block will
     492                 * be written no matter what. This will usually (unless the
     493                 * backend has some further optimization enabled) cause the
     494                 * block to be allocated. */
     495                rc = vdWriteHelperStandard(pDisk, pImage, uOffset, cbWrite,
     496                                           cbThisWrite, cbPreRead, cbPostRead,
     497                                           pvBuf, pvTmp);
     498            }
     499            RTMemTmpFree(pvTmp);
     500            if (VBOX_FAILURE(rc))
     501                break;
     502        }
     503
     504        cbWrite -= cbThisWrite;
     505        uOffset += cbThisWrite;
     506        pvBuf = (char *)pvBuf + cbThisWrite;
     507    } while (cbWrite != 0 && VBOX_SUCCESS(rc));
     508
     509    return rc;
     510}
     511
     512
     513/**
     514 * Allocates and initializes an empty HDD container.
    465515 * No image files are opened.
    466516 *
     
    469519 * @param   pfnError        Callback for setting extended error information.
    470520 * @param   pvErrorUser     Opaque parameter for pfnError.
    471  * @param   ppDisk          Where to store the reference to the VBox HDD container.
     521 * @param   ppDisk          Where to store the reference to HDD container.
    472522 */
    473523VBOXDDU_DECL(int) VDCreate(const char *pszBackend, PFNVDERROR pfnError,
     
    475525{
    476526    int rc = VINF_SUCCESS;
    477     PVBOXHDDBACKEND pBackend = NULL;
     527    PCVBOXHDDBACKEND pBackend = NULL;
    478528    PVBOXHDD pDisk = NULL;
    479 
    480     /* Passing an error callback is strictly not necessary any more. Any code
    481      * calling the HDD container functions should provide one, as otherwise
    482      * many detailed error messages will go unnoticed. If you find a situation
    483      * where you get no sensible error message from this code but you think
    484      * there should be one, shout loudly. There are no error messages for rare
    485      * and obvious error codes such as VERR_NO_MEMORY, and for situations which
    486      * the user cannot be made responsible for, such as program bugs causing
    487      * parameter checks to fail etc. */
    488     Assert(pfnError);
    489 
    490     /* Find backend. */
    491     for (unsigned i = 0; aBackends[i].pszBackendName != NULL; i++)
    492     {
    493         if (!strcmp(pszBackend, aBackends[i].pszBackendName))
    494         {
    495             pBackend = aBackends[i].Backend;
    496             break;
    497         }
    498     }
    499 
    500     /* If no static backend is found try loading a shared module with pszBackend as filename. */
    501     if (!pBackend)
    502     {
    503         RTLDRMOD hPlugin;
    504         char *pszPluginName;
    505         int cbPluginName;
    506 
    507         /* HDD Format Plugins have VBoxHDD as prefix, thatswhy we have to prepend it.
    508          * @todo: find out what to do if filenames are case sensitive.
    509          */
    510         cbPluginName = RTStrAPrintf(&pszPluginName, "%s%s", VBOX_HDDFORMAT_PLUGIN_PREFIX, pszBackend);
    511         if (cbPluginName == -1)
    512         {
    513             rc = VERR_NO_MEMORY;
    514         }
    515         else
    516         {
    517             /* Try to load the plugin (RTLdrLoad appends the suffix for the shared object/DLL). */
     529    RTLDRMOD hPlugin = NULL;
     530
     531    LogFlowFunc(("pszBackend=\"%s\" pfnError=%#p pvErrorUser=%#p\n",
     532                 pszBackend, pfnError, pvErrorUser));
     533    do
     534    {
     535        /* Check arguments. */
     536        AssertMsgBreak(VALID_PTR(pszBackend) && *pszBackend,
     537                       ("pszBackend=%#p \"%s\"\n", pszBackend, pszBackend),
     538                       rc = VERR_INVALID_PARAMETER);
     539        AssertMsgBreak(VALID_PTR(pfnError),
     540                       ("pfnError=%#p\n", pfnError),
     541                       rc = VERR_INVALID_PARAMETER);
     542        AssertMsgBreak(VALID_PTR(ppDisk),
     543                       ("ppDisk=%#p\n", ppDisk),
     544                       rc = VERR_INVALID_PARAMETER);
     545
     546        /* Find backend. */
     547        for (unsigned i = 0; aBackends[i] != NULL; i++)
     548        {
     549            if (!strcmp(pszBackend, aBackends[i]->pszBackendName))
     550            {
     551                pBackend = aBackends[i];
     552                break;
     553            }
     554        }
     555
     556        /* If no static backend is found try loading a shared module with
     557         * pszBackend as filename. */
     558        if (!pBackend)
     559        {
     560            char *pszPluginName;
     561
     562            /* HDD Format Plugins have VBoxHDD as prefix, prepend it. */
     563            RTStrAPrintf(&pszPluginName, "%s%s",
     564                         VBOX_HDDFORMAT_PLUGIN_PREFIX, pszBackend);
     565            if (!pszPluginName)
     566            {
     567                rc = VERR_NO_MEMORY;
     568                break;
     569            }
     570
     571            /* Try to load the plugin (RTldrLoad takes care of the suffix). */
    518572            rc = RTLdrLoad(pszPluginName, &hPlugin);
    519573            if (VBOX_SUCCESS(rc))
     
    521575                PFNVBOXHDDFORMATLOAD pfnHDDFormatLoad;
    522576
    523                 rc = RTLdrGetSymbol(hPlugin, VBOX_HDDFORMAT_LOAD_NAME, (void**)&pfnHDDFormatLoad);
     577                rc = RTLdrGetSymbol(hPlugin, VBOX_HDDFORMAT_LOAD_NAME,
     578                                    (void**)&pfnHDDFormatLoad);
     579                if (VBOX_FAILURE(rc) || !pfnHDDFormatLoad)
     580                {
     581                    LogFunc(("error resolving the entry point %s in plugin %s, rc=%Vrc, pfnHDDFormat=%#p\n", VBOX_HDDFORMAT_LOAD_NAME, pszPluginName, rc, pfnHDDFormatLoad));
     582                    if (VBOX_SUCCESS(rc))
     583                        rc = VERR_SYMBOL_NOT_FOUND;
     584                    break;
     585                }
     586
     587                /* Get the function table. */
     588                PVBOXHDDBACKEND pBE;
     589                rc = pfnHDDFormatLoad(&pBE);
    524590                if (VBOX_FAILURE(rc))
     591                    break;
     592                /* Check if the sizes match. If not this plugin is too old. */
     593                if (pBE->cbSize != sizeof(VBOXHDDBACKEND))
    525594                {
    526                     Log(("%s: Error resolving the entry point %s, rc = %d, pfnHDDFormat = %p\n", VBOX_HDDFORMAT_LOAD_NAME, rc, pfnHDDFormatLoad));
    527                     if (VBOX_SUCCESS(rc))
    528                        rc = VERR_SYMBOL_NOT_FOUND;
     595                    rc = VERR_VDI_UNSUPPORTED_VERSION;
     596                    break;
    529597                }
    530                 else
    531                 {
    532                     /* Get the function table. */
    533                     rc = pfnHDDFormatLoad(&pBackend);
    534                     if (VBOX_FAILURE(rc))
    535                         pBackend = NULL;
    536 
    537                     /*
    538                      * Check if the sizes match.
    539                      * If not this plugin is too old to load.
    540                      */
    541                     if (pBackend->cbSize != sizeof(VBOXHDDBACKEND))
    542                     {
    543                         rc = VERR_VDI_UNSUPPORTED_VERSION;
    544                         pBackend = NULL;
    545                         RTLdrClose(hPlugin);
    546                     }
    547                 }
     598                pBackend = pBE;
    548599            }
     600
    549601            RTStrFree(pszPluginName);
    550602        }
    551     }
    552 
    553     if (pBackend)
    554     {
    555         pDisk = (PVBOXHDD)RTMemAllocZ(sizeof(VBOXHDD));
     603
     604        if (pBackend)
     605        {
     606            pDisk = (PVBOXHDD)RTMemAllocZ(sizeof(VBOXHDD));
     607            if (pDisk)
     608            {
     609                pDisk->u32Signature = VBOXHDDDISK_SIGNATURE;
     610                pDisk->cImages      = 0;
     611                pDisk->pBase        = NULL;
     612                pDisk->pLast        = NULL;
     613                pDisk->cbSize       = 0;
     614                pDisk->PCHSGeometry.cCylinders = 0;
     615                pDisk->PCHSGeometry.cHeads     = 0;
     616                pDisk->PCHSGeometry.cSectors   = 0;
     617                pDisk->LCHSGeometry.cCylinders = 0;
     618                pDisk->LCHSGeometry.cHeads     = 0;
     619                pDisk->LCHSGeometry.cSectors   = 0;
     620                pDisk->pfnError     = pfnError;
     621                pDisk->pvErrorUser  = pvErrorUser;
     622                pDisk->Backend      = pBackend;
     623                pDisk->hPlugin      = hPlugin;
     624                *ppDisk = pDisk;
     625            }
     626            else
     627            {
     628                rc = VERR_NO_MEMORY;
     629                break;
     630            }
     631        }
     632        else
     633            rc = vdEarlyError(pfnError, pvErrorUser, VERR_INVALID_PARAMETER,
     634                              RT_SRC_POS, "VD: unknown backend name '%s'",
     635                              pszBackend);
     636    } while (0);
     637
     638    if (VBOX_FAILURE(rc) && hPlugin)
     639        RTLdrClose(hPlugin);
     640
     641    LogFlowFunc(("returns %Vrc (pDisk=%#p)\n", rc, pDisk));
     642    return rc;
     643}
     644
     645/**
     646 * Destroys HDD container.
     647 * If container has opened image files they will be closed.
     648 *
     649 * @param   pDisk           Pointer to HDD container.
     650 */
     651VBOXDDU_DECL(void) VDDestroy(PVBOXHDD pDisk)
     652{
     653    LogFlowFunc(("pDisk=%#p\n", pDisk));
     654    do
     655    {
     656        /* sanity check */
     657        AssertBreak(VALID_PTR(pDisk), );
     658        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     659
    556660        if (pDisk)
    557661        {
    558             pDisk->u32Signature = VBOXHDDDISK_SIGNATURE;
    559             pDisk->cImages      = 0;
    560             pDisk->pBase        = NULL;
    561             pDisk->pLast        = NULL;
    562             pDisk->cbSize       = 0;
    563             pDisk->cCylinders   = 0;
    564             pDisk->cHeads       = 0;
    565             pDisk->cSectors     = 0;
    566             pDisk->pfnError     = pfnError;
    567             pDisk->pvErrorUser  = pvErrorUser;
    568             pDisk->Backend      = pBackend;
    569             pDisk->hPlugin      = NIL_RTLDRMOD;
    570             *ppDisk = pDisk;
    571         }
    572         else
    573             rc = VERR_NO_MEMORY;
    574     }
    575     else
    576         rc = vdEarlyError(pfnError, pvErrorUser, VERR_INVALID_PARAMETER,
    577                           RT_SRC_POS, "VD: unknown backend name '%s'",
    578                           pszBackend);
    579 
    580     LogFlow(("%s: returns %Vrc (pDisk=%#p)\n", __FUNCTION__, rc, pDisk));
    581     return rc;
    582 }
    583 
    584 /**
    585  * Try to get the backend name which can use this image.
     662            VDCloseAll(pDisk);
     663            if (pDisk->hPlugin != NIL_RTLDRMOD)
     664            {
     665                RTLdrClose(pDisk->hPlugin);
     666                pDisk->hPlugin = NIL_RTLDRMOD;
     667            }
     668            RTMemFree(pDisk);
     669        }
     670    } while (0);
     671    LogFlowFunc(("returns\n"));
     672}
     673
     674/**
     675 * Try to get the backend name which can use this image.
    586676 *
    587677 * @returns VBox status code.
     
    590680 *          VERR_NOT_SUPPORTED if no plugin was found.
    591681 * @param   pszFilename     Name of the image file for which the backend is queried.
    592  * @param   ppszFormat      Where to store the name of the plugin.
     682 * @param   ppszFormat      Receives pointer of the UTF-8 string which contains the format name.
     683 *                          The returned pointer must be freed using RTStrFree().
    593684 */
    594685VBOXDDU_DECL(int) VDGetFormat(const char *pszFilename, char **ppszFormat)
    595686{
    596     char pszProgramPath[1024]; /* Far too much I think but to be on the safe side. */
    597     char *pszPluginFilter;
    598687    PRTDIR pPluginDir = NULL;
    599     PRTDIRENTRY pPluginDirEntry = NULL;
    600     unsigned cbPluginDirEntry;
    601688    int rc = VERR_NOT_SUPPORTED;
    602689    int rcCheck = VINF_SUCCESS;
    603690    bool fPluginFound = false;
    604691
    605     if (!ppszFormat)
    606         return VERR_INVALID_PARAMETER;
     692    LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
     693    do
     694    {
     695        /* Check arguments. */
     696        AssertMsgBreak(VALID_PTR(pszFilename) && *pszFilename,
     697                       ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename),
     698                       rc = VERR_INVALID_PARAMETER);
     699        AssertMsgBreak(VALID_PTR(ppszFormat),
     700                       ("ppszFormat=%#p\n", ppszFormat),
     701                       rc = VERR_INVALID_PARAMETER);
    607702       
    608     memset(pszProgramPath, 0, 1024);
    609     rc = RTPathProgram(pszProgramPath, 1024);
    610     if (VBOX_FAILURE(rc))
    611         return rc;
    612 
    613     /* To get all entries with VBoxHDD as prefix. */
    614     rc = RTStrAPrintf(&pszPluginFilter, "%s/%s*", pszProgramPath, VBOX_HDDFORMAT_PLUGIN_PREFIX);
    615     if (VBOX_FAILURE(rc))
    616     {
    617         RTStrFree(pszProgramPath);
    618         return VERR_NO_MEMORY;
    619     }
    620 
    621     /* The plugins are in the same directory as the program. */
    622     rc = RTDirOpenFiltered(&pPluginDir, pszPluginFilter, RTDIRFILTER_WINNT);
    623     if (VBOX_FAILURE(rc))
    624         goto out;
    625 
    626     pPluginDirEntry = (PRTDIRENTRY)RTMemAllocZ(sizeof(RTDIRENTRY));
    627     if (!pPluginDir)
    628     {
    629         rc = VERR_NO_MEMORY;
    630         goto out;
    631     }
    632 
    633     while ((rc = RTDirRead(pPluginDir, pPluginDirEntry, &cbPluginDirEntry)) != VERR_NO_MORE_FILES)
    634     {
    635         RTLDRMOD hPlugin = NIL_RTLDRMOD;
    636         PFNVBOXHDDFORMATLOAD pfnHDDFormatLoad = NULL;
    637         PVBOXHDDBACKEND pBackend = NULL;
    638 
    639         if (rc == VERR_BUFFER_OVERFLOW)
    640         {
    641             /* allocate new buffer. */
    642             RTMemFree(pPluginDirEntry);
    643             pPluginDirEntry = (PRTDIRENTRY)RTMemAllocZ(cbPluginDirEntry);
    644             /* Retry. */
    645             rc = RTDirRead(pPluginDir, pPluginDirEntry, &cbPluginDirEntry);
    646         }
    647 
     703        /* First check if static backends support this file format. */
     704        for (unsigned i = 0; aBackends[i] != NULL; i++)
     705        {
     706            if (aBackends[i]->pfnCheckIfValid)
     707            {
     708                rc = aBackends[i]->pfnCheckIfValid(pszFilename);
     709                if (VBOX_SUCCESS(rc))
     710                {
     711                    fPluginFound = true;
     712                    /* Copy the name into the new string. */
     713                    char *pszFormat = RTStrDup(aBackends[i]->pszBackendName);
     714                    if (!pszFormat)
     715                    {
     716                        rc = VERR_NO_MEMORY;
     717                        break;
     718                    }
     719                    *ppszFormat = pszFormat;
     720                    break;
     721                }
     722            }
     723        }
     724
     725        /* Then check if plugin backends support this file format. */
     726        char szPath[RTPATH_MAX];
     727        rc = RTPathSharedLibs(szPath, sizeof(szPath));
    648728        if (VBOX_FAILURE(rc))
    649729            break;
    650730
    651         /* We got the new entry. */
    652         if (pPluginDirEntry->enmType != RTDIRENTRYTYPE_FILE)
    653             continue;
    654 
    655         rc = RTLdrLoad(pPluginDirEntry->szName, &hPlugin);
    656         if (VBOX_SUCCESS(rc))
    657         {
    658             rc = RTLdrGetSymbol(hPlugin, VBOX_HDDFORMAT_LOAD_NAME, (void**)&pfnHDDFormatLoad);
    659             if (VBOX_FAILURE(rc) || !pfnHDDFormatLoad)
     731        /* To get all entries with VBoxHDD as prefix. */
     732        char *pszPluginFilter;
     733        rc = RTStrAPrintf(&pszPluginFilter, "%s/%s*", szPath,
     734                          VBOX_HDDFORMAT_PLUGIN_PREFIX);
     735        if (VBOX_FAILURE(rc))
     736        {
     737            rc = VERR_NO_MEMORY;
     738            break;
     739        }
     740
     741        /* The plugins are in the same directory as the other shared libs. */
     742        rc = RTDirOpenFiltered(&pPluginDir, pszPluginFilter, RTDIRFILTER_WINNT);
     743        if (VBOX_FAILURE(rc))
     744            break;
     745
     746        PRTDIRENTRY pPluginDirEntry = NULL;
     747        unsigned cbPluginDirEntry;
     748        pPluginDirEntry = (PRTDIRENTRY)RTMemAllocZ(sizeof(RTDIRENTRY));
     749        if (!pPluginDir)
     750        {
     751            rc = VERR_NO_MEMORY;
     752            break;
     753        }
     754
     755        while ((rc = RTDirRead(pPluginDir, pPluginDirEntry, &cbPluginDirEntry)) != VERR_NO_MORE_FILES)
     756        {
     757            RTLDRMOD hPlugin = NIL_RTLDRMOD;
     758            PFNVBOXHDDFORMATLOAD pfnHDDFormatLoad = NULL;
     759            PVBOXHDDBACKEND pBackend = NULL;
     760
     761            if (rc == VERR_BUFFER_OVERFLOW)
    660762            {
    661                 Log(("%s: Error resolving the entry point %s, rc = %d, pfnHDDFormat = %p\n", VBOX_HDDFORMAT_LOAD_NAME, rc, pfnHDDFormatLoad));
     763                /* allocate new buffer. */
     764                RTMemFree(pPluginDirEntry);
     765                pPluginDirEntry = (PRTDIRENTRY)RTMemAllocZ(cbPluginDirEntry);
     766                /* Retry. */
     767                rc = RTDirRead(pPluginDir, pPluginDirEntry, &cbPluginDirEntry);
     768                if (VBOX_FAILURE(rc))
     769                    break;
     770            }
     771            else if (VBOX_FAILURE(rc))
     772                break;
     773
     774            /* We got the new entry. */
     775            if (pPluginDirEntry->enmType != RTDIRENTRYTYPE_FILE)
     776                continue;
     777
     778            rc = RTLdrLoad(pPluginDirEntry->szName, &hPlugin);
     779            if (VBOX_SUCCESS(rc))
     780            {
     781                rc = RTLdrGetSymbol(hPlugin, VBOX_HDDFORMAT_LOAD_NAME, (void**)&pfnHDDFormatLoad);
     782                if (VBOX_FAILURE(rc) || !pfnHDDFormatLoad)
     783                {
     784                    LogFunc(("error resolving the entry point %s in plugin %s, rc=%Vrc, pfnHDDFormat=%#p\n", VBOX_HDDFORMAT_LOAD_NAME, pPluginDirEntry->szName, rc, pfnHDDFormatLoad));
     785                    if (VBOX_SUCCESS(rc))
     786                        rc = VERR_SYMBOL_NOT_FOUND;
     787                }
     788
    662789                if (VBOX_SUCCESS(rc))
    663                     rc = VERR_SYMBOL_NOT_FOUND;
    664             }
    665             else
    666             {
    667                 rc = pfnHDDFormatLoad(&pBackend);
    668                 if (VBOX_SUCCESS(rc) && (pBackend->cbSize == sizeof(VBOXHDDBACKEND)))
    669790                {
    670                     /* Check if the plugin can handle this file. */
    671                     rcCheck = pBackend->pfnCheckIfValid(pszFilename);
    672                     if (VBOX_SUCCESS(rcCheck))
     791                    /* Get the function table. */
     792                    rc = pfnHDDFormatLoad(&pBackend);
     793                    if (VBOX_SUCCESS(rc) && pBackend->cbSize == sizeof(VBOXHDDBACKEND))
    673794                    {
    674                         fPluginFound = true;
    675 
    676                         /* Report the format name. */
    677                         char *pszName = pPluginDirEntry->szName + VBOX_HDDFORMAT_PLUGIN_PREFIX_LENGTH; /* Point to the rest after the prefix. */
    678                         char *pszFormat = NULL;
    679                         unsigned cbFormat = 0;
    680                            
    681                         while((*pszName != '.') && (*pszName != '\0'))
     795
     796                        /* Check if the plugin can handle this file. */
     797                        rc = pBackend->pfnCheckIfValid(pszFilename);
     798                        if (VBOX_SUCCESS(rc))
    682799                        {
    683                             cbFormat++;
    684                             pszName++;
    685                         }
    686 
    687                         pszName = pPluginDirEntry->szName + VBOX_HDDFORMAT_PLUGIN_PREFIX_LENGTH;
    688 
    689                         /* Copy the name into the new string. */   
    690                         pszFormat = (char *)RTMemAllocZ(cbFormat+1);
    691 
    692                         if (pszFormat)
    693                         {
    694                             memcpy(pszFormat, pszName, cbFormat);
     800                            fPluginFound = true;
     801                            rc = VINF_SUCCESS;
     802
     803                            /* Report the format name. */
     804                            RTPathStripExt(pPluginDirEntry->szName);
     805                            char *pszFormat = NULL;
     806                            AssertBreak(strlen(pszFormat) >= VBOX_HDDFORMAT_PLUGIN_PREFIX_LENGTH,
     807                                        rc = VERR_INVALID_NAME);
     808                            pszFormat = RTStrDup(pPluginDirEntry->szName + VBOX_HDDFORMAT_PLUGIN_PREFIX_LENGTH);
     809                            if (!pszFormat)
     810                                rc = VERR_NO_MEMORY;
    695811                            *ppszFormat = pszFormat;
    696812                        }
    697                         else
    698                             rc = VERR_NO_MEMORY;
    699813                    }
    700                     else
    701                         rcCheck = VERR_NOT_SUPPORTED;
    702814                }
    703815                else
     
    711823                break;
    712824        }
    713     }
    714 
    715 out:
    716     if (pPluginDirEntry)
    717         RTMemFree(pPluginDirEntry);
    718     if (pPluginDir)
    719         RTDirClose(pPluginDir);
    720 
    721     RTStrFree(pszPluginFilter);
    722     RTStrFree(pszProgramPath);
    723 
    724     if ((fPluginFound == true) && (*ppszFormat != NULL))
    725         rc = VINF_SUCCESS;
    726     else if ((rcCheck == VERR_NOT_SUPPORTED) && (rc == VINF_SUCCESS))
    727         rc = rcCheck;
    728 
    729     return rc;
    730 }
    731 
    732 /**
    733  * Destroys the VBox HDD container.
    734  * If container has opened image files they will be closed.
    735  *
    736  * @param   pDisk           Pointer to VBox HDD container.
    737  */
    738 VBOXDDU_DECL(void) VDDestroy(PVBOXHDD pDisk)
    739 {
    740     LogFlow(("%s: pDisk=%#p\n", __FUNCTION__, pDisk));
    741     /* sanity check */
    742     Assert(pDisk);
    743     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    744 
    745     if (pDisk)
    746     {
    747         VDCloseAll(pDisk);
    748         if (pDisk->hPlugin != NIL_RTLDRMOD)
    749         {
    750             RTLdrClose(pDisk->hPlugin);
    751             pDisk->hPlugin = NIL_RTLDRMOD;
    752         }
    753         RTMemFree(pDisk);
    754     }
     825        RTStrFree(pszPluginFilter);
     826        if (pPluginDirEntry)
     827            RTMemFree(pPluginDirEntry);
     828        if (pPluginDir)
     829            RTDirClose(pPluginDir);
     830    } while (0);
     831
     832    LogFlowFunc(("returns %Vrc *ppszFormat=\"%s\"\n", rc, *ppszFormat));
     833    return rc;
    755834}
    756835
     
    758837 * Opens an image file.
    759838 *
    760  * The first opened image file in a HDD container must have a base image type,
     839 * The first opened image file in HDD container must have a base image type,
    761840 * others (next opened images) must be a differencing or undo images.
    762841 * Linkage is checked for differencing image to be in consistence with the previously opened image.
     
    765844 * other processes to use images in read-only mode too.
    766845 *
    767  * Note that the image can be opened in read-only mode if a read/write open is not possible.
     846 * Note that the image is opened in read-only mode if a read/write open is not possible.
    768847 * Use VDIsReadOnly to check open mode.
    769848 *
    770849 * @returns VBox status code.
    771  * @param   pDisk           Pointer to VBox HDD container.
     850 * @param   pDisk           Pointer to HDD container.
    772851 * @param   pszFilename     Name of the image file to open.
    773852 * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
     
    777856{
    778857    int rc = VINF_SUCCESS;
    779     LogFlow(("%s: pszFilename=\"%s\" uOpenFlags=%#x\n", __FUNCTION__,
    780              pszFilename, uOpenFlags));
    781     /* sanity check */
    782     Assert(pDisk);
    783     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    784 
    785     /* Check arguments. */
    786     if (    !pszFilename
    787         ||  *pszFilename == '\0'
    788         ||  (uOpenFlags & ~VD_OPEN_FLAGS_MASK))
    789     {
    790         AssertMsgFailed(("Invalid arguments: pszFilename=%#p uOpenFlags=%#x\n", pszFilename, uOpenFlags));
    791         return VERR_INVALID_PARAMETER;
    792     }
    793 
    794     /* Force readonly for images without base/diff consistency checking. */
    795     if (uOpenFlags & VD_OPEN_FLAGS_INFO)
    796         uOpenFlags |= VD_OPEN_FLAGS_READONLY;
    797 
    798     /* Set up image descriptor. */
    799     PVDIMAGE pImage = (PVDIMAGE)RTMemAllocZ(sizeof(VDIMAGE));
    800     if (!pImage)
    801         return VERR_NO_MEMORY;
    802     pImage->pszFilename = RTStrDup(pszFilename);
    803     if (!pImage->pszFilename)
    804         rc = VERR_NO_MEMORY;
    805 
    806     if (VBOX_SUCCESS(rc))
    807     {
     858    PVDIMAGE pImage = NULL;
     859
     860    LogFlowFunc(("pDisk=%#p pszFilename=\"%s\" uOpenFlags=%#x\n",
     861                 pszFilename, uOpenFlags));
     862    do
     863    {
     864        /* sanity check */
     865        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     866        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     867
     868        /* Check arguments. */
     869        AssertMsgBreak(VALID_PTR(pszFilename) && *pszFilename,
     870                       ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename),
     871                       rc = VERR_INVALID_PARAMETER);
     872        AssertMsgBreak((uOpenFlags & ~VD_OPEN_FLAGS_MASK) == 0,
     873                       ("uOpenFlags=%#x\n", uOpenFlags),
     874                       rc = VERR_INVALID_PARAMETER);
     875
     876        /* Force readonly for images without base/diff consistency checking. */
     877        if (uOpenFlags & VD_OPEN_FLAGS_INFO)
     878            uOpenFlags |= VD_OPEN_FLAGS_READONLY;
     879
     880        /* Set up image descriptor. */
     881        pImage = (PVDIMAGE)RTMemAllocZ(sizeof(VDIMAGE));
     882        if (!pImage)
     883        {
     884            rc = VERR_NO_MEMORY;
     885            break;
     886        }
     887        pImage->pszFilename = RTStrDup(pszFilename);
     888        if (!pImage->pszFilename)
     889        {
     890            rc = VERR_NO_MEMORY;
     891            break;
     892        }
     893
    808894        pImage->uOpenFlags = uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME;
    809895        rc = pDisk->Backend->pfnOpen(pImage->pszFilename,
     
    811897                                     pDisk->pfnError, pDisk->pvErrorUser,
    812898                                     &pImage->pvBackendData);
    813     }
    814     /* If the open in read-write mode failed, retry in read-only mode. */
    815     if (VBOX_FAILURE(rc))
    816     {
    817         if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY)
    818             &&  (rc == VERR_ACCESS_DENIED
    819                  || rc == VERR_PERMISSION_DENIED
    820                  || rc == VERR_WRITE_PROTECT
    821                  || rc == VERR_SHARING_VIOLATION
    822                  || rc == VERR_FILE_LOCK_FAILED))
    823             rc = pDisk->Backend->pfnOpen(pImage->pszFilename,
    824                                            (uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME)
    825                                          | VD_OPEN_FLAGS_READONLY,
    826                                          pDisk->pfnError, pDisk->pvErrorUser,
    827                                          &pImage->pvBackendData);
     899        /* If the open in read-write mode failed, retry in read-only mode. */
    828900        if (VBOX_FAILURE(rc))
    829             rc = vdError(pDisk, rc, RT_SRC_POS,
    830                          N_("VD: error opening image file '%s'"), pszFilename);
    831     }
    832 
    833     if (VBOX_SUCCESS(rc))
    834     {
     901        {
     902            if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY)
     903                &&  (rc == VERR_ACCESS_DENIED
     904                     || rc == VERR_PERMISSION_DENIED
     905                     || rc == VERR_WRITE_PROTECT
     906                     || rc == VERR_SHARING_VIOLATION
     907                     || rc == VERR_FILE_LOCK_FAILED))
     908                rc = pDisk->Backend->pfnOpen(pImage->pszFilename,
     909                                               (uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME)
     910                                             | VD_OPEN_FLAGS_READONLY,
     911                                             pDisk->pfnError, pDisk->pvErrorUser,
     912                                             &pImage->pvBackendData);
     913            if (VBOX_FAILURE(rc))
     914            {
     915                rc = vdError(pDisk, rc, RT_SRC_POS,
     916                             N_("VD: error opening image file '%s'"), pszFilename);
     917                break;
     918            }
     919        }
     920
    835921        VDIMAGETYPE enmImageType;
    836922        rc = pDisk->Backend->pfnGetImageType(pImage->pvBackendData,
     
    843929            &&  pDisk->cImages != 0
    844930            &&  enmImageType != VD_IMAGE_TYPE_NORMAL)
     931        {
    845932            rc = VERR_VDI_INVALID_TYPE;
     933            break;
     934        }
    846935
    847936        /** @todo optionally check UUIDs */
    848937
    849         if (VBOX_SUCCESS(rc))
    850         {
    851             uint64_t cbSize = pDisk->Backend->pfnGetSize(pImage->pvBackendData);
    852             if (pDisk->cImages == 0)
    853             {
    854                 /* Cache disk information. */
    855                 pDisk->cbSize = cbSize;
    856 
    857                 /* Cache CHS geometry. */
    858                 int rc2 = pDisk->Backend->pfnGetGeometry(pImage->pvBackendData,
    859                                                          &pDisk->cCylinders,
    860                                                          &pDisk->cHeads,
    861                                                          &pDisk->cSectors);
    862                 if (VBOX_FAILURE(rc2))
    863                 {
    864                     pDisk->cCylinders = 0;
    865                     pDisk->cHeads = 0;
    866                     pDisk->cSectors = 0;
    867                 }
    868                 else
    869                 {
    870                     /* Make sure the CHS geometry is properly clipped. */
    871                     pDisk->cCylinders = RT_MIN(pDisk->cCylinders, 16383);
    872                     pDisk->cHeads = RT_MIN(pDisk->cHeads, 255);
    873                     pDisk->cSectors = RT_MIN(pDisk->cSectors, 255);
    874                 }
    875 
    876                 /* Cache translation mode. */
    877                 rc2 = pDisk->Backend->pfnGetTranslation(pImage->pvBackendData,
    878                                                         &pDisk->enmTranslation);
    879                 if (VBOX_FAILURE(rc2))
    880                     pDisk->enmTranslation = (PDMBIOSTRANSLATION)0;
    881             }
    882             else
    883             {
    884                 /* Check image size/block size for consistency. */
    885                 if (cbSize != pDisk->cbSize)
    886                     rc = VERR_VDI_INVALID_TYPE;
    887             }
    888         }
    889 
    890         if (VBOX_SUCCESS(rc) && pDisk->cImages != 0)
     938        int rc2;
     939
     940        /* Cache disk information. */
     941        pDisk->cbSize = pDisk->Backend->pfnGetSize(pImage->pvBackendData);
     942
     943        /* Cache PCHS geometry. */
     944        rc2 = pDisk->Backend->pfnGetPCHSGeometry(pImage->pvBackendData,
     945                                                 &pDisk->PCHSGeometry);
     946        if (VBOX_FAILURE(rc2))
     947        {
     948            pDisk->PCHSGeometry.cCylinders = 0;
     949            pDisk->PCHSGeometry.cHeads = 0;
     950            pDisk->PCHSGeometry.cSectors = 0;
     951        }
     952        else
     953        {
     954            /* Make sure the PCHS geometry is properly clipped. */
     955            pDisk->PCHSGeometry.cCylinders = RT_MIN(pDisk->PCHSGeometry.cCylinders, 16383);
     956            pDisk->PCHSGeometry.cHeads = RT_MIN(pDisk->PCHSGeometry.cHeads, 16);
     957            pDisk->PCHSGeometry.cSectors = RT_MIN(pDisk->PCHSGeometry.cSectors, 63);
     958        }
     959
     960        /* Cache LCHS geometry. */
     961        rc2 = pDisk->Backend->pfnGetLCHSGeometry(pImage->pvBackendData,
     962                                                 &pDisk->LCHSGeometry);
     963        if (VBOX_FAILURE(rc2))
     964        {
     965            pDisk->LCHSGeometry.cCylinders = 0;
     966            pDisk->LCHSGeometry.cHeads = 0;
     967            pDisk->LCHSGeometry.cSectors = 0;
     968        }
     969        else
     970        {
     971            /* Make sure the LCHS geometry is properly clipped. */
     972            pDisk->LCHSGeometry.cCylinders = RT_MIN(pDisk->LCHSGeometry.cCylinders, 1024);
     973            pDisk->LCHSGeometry.cHeads = RT_MIN(pDisk->LCHSGeometry.cHeads, 255);
     974            pDisk->LCHSGeometry.cSectors = RT_MIN(pDisk->LCHSGeometry.cSectors, 63);
     975        }
     976
     977        if (pDisk->cImages != 0)
    891978        {
    892979            /* Switch previous image to read-only mode. */
     
    9131000            pImage->pvBackendData = NULL;
    9141001        }
    915     }
     1002    } while (0);
    9161003
    9171004    if (VBOX_FAILURE(rc))
     
    9251012    }
    9261013
    927     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     1014    LogFlowFunc(("returns %Vrc\n", rc));
    9281015    return rc;
    9291016}
     
    9331020 *
    9341021 * @returns VBox status code.
    935  * @param   pDisk           Pointer to VBox HDD container.
     1022 * @param   pDisk           Pointer to HDD container.
    9361023 * @param   pszFilename     Name of the image file to create.
    9371024 * @param   enmType         Image type, only base image types are acceptable.
     
    9391026 * @param   uImageFlags     Flags specifying special image features.
    9401027 * @param   pszComment      Pointer to image comment. NULL is ok.
    941  * @param   cCylinders      Number of cylinders (must be <= 16383).
    942  * @param   cHeads          Number of heads (must be <= 16).
    943  * @param   cSectors        Number of sectors (must be <= 63);
     1028 * @param   pPCHSGeometry   Pointer to physical disk geometry <= (16383,16,63). Not NULL.
     1029 * @param   pLCHSGeometry   Pointer to logical disk geometry <= (1024,255,63). Not NULL.
    9441030 * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
    9451031 * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
     
    9491035                               VDIMAGETYPE enmType, uint64_t cbSize,
    9501036                               unsigned uImageFlags, const char *pszComment,
    951                                unsigned cCylinders, unsigned cHeads,
    952                                unsigned cSectors, unsigned uOpenFlags,
    953                                PFNVMPROGRESS pfnProgress, void *pvUser)
     1037                               PCPDMMEDIAGEOMETRY pPCHSGeometry,
     1038                               PCPDMMEDIAGEOMETRY pLCHSGeometry,
     1039                               unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
     1040                               void *pvUser)
    9541041{
    9551042    int rc = VINF_SUCCESS;
    956     LogFlow(("%s: pszFilename=\"%s\" uOpenFlags=%#x\n", __FUNCTION__,
    957              pszFilename, uOpenFlags));
    958     /* sanity check */
    959     Assert(pDisk);
    960     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    961 
    962     /* Check arguments. */
    963     if (    !pszFilename
    964         ||  *pszFilename == '\0'
    965         ||  (enmType != VD_IMAGE_TYPE_NORMAL && enmType != VD_IMAGE_TYPE_FIXED)
    966         ||  !cbSize
    967         ||  (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
    968         ||  cCylinders == 0
    969         ||  cCylinders > 16383
    970         ||  cHeads == 0
    971         ||  cHeads > 16
    972         ||  cSectors == 0
    973         ||  cSectors > 63)
    974     {
    975         AssertMsgFailed(("Invalid arguments: pszFilename=%#p uOpenFlags=%#x\n", pszFilename, uOpenFlags));
    976         return VERR_INVALID_PARAMETER;
    977     }
    978 
    979     /* Check state. */
    980     if (pDisk->cImages != 0)
    981     {
    982         AssertMsgFailed(("Create base image cannot be done with other images open\n"));
    983         return VERR_VDI_INVALID_STATE;
    984     }
    985 
    986     /* Set up image descriptor. */
    987     PVDIMAGE pImage = (PVDIMAGE)RTMemAllocZ(sizeof(VDIMAGE));
    988     if (!pImage)
    989         return VERR_NO_MEMORY;
    990     pImage->pszFilename = RTStrDup(pszFilename);
    991     if (!pImage->pszFilename)
    992         rc = VERR_NO_MEMORY;
    993 
    994     if (VBOX_SUCCESS(rc))
     1043    PVDIMAGE pImage = NULL;
     1044
     1045    LogFlowFunc(("pszFilename=\"%s\" enmType=%#x cbSize=%llu uImageFlags=%#x pszComment=\"%s\" PCHS=%u/%u/%u LCHS=%u/%u/%u uOpenFlags=%#x pfnProgress=%#p pvUser=%#p\n",
     1046                 pszFilename, enmType, cbSize, uImageFlags, pszComment,
     1047                 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads,
     1048                 pPCHSGeometry->cSectors, pLCHSGeometry->cCylinders,
     1049                 pLCHSGeometry->cHeads, pLCHSGeometry->cSectors, uOpenFlags,
     1050                 pfnProgress, pvUser));
     1051    do
     1052    {
     1053        /* sanity check */
     1054        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     1055        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1056
     1057        /* Check arguments. */
     1058        AssertMsgBreak(VALID_PTR(pszFilename) && *pszFilename,
     1059                       ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename),
     1060                       rc = VERR_INVALID_PARAMETER);
     1061        AssertMsgBreak(enmType == VD_IMAGE_TYPE_NORMAL || enmType == VD_IMAGE_TYPE_FIXED,
     1062                       ("enmType=%#x\n", enmType),
     1063                       rc = VERR_INVALID_PARAMETER);
     1064        AssertMsgBreak(cbSize,
     1065                       ("cbSize=%llu\n", cbSize),
     1066                       rc = VERR_INVALID_PARAMETER);
     1067        AssertMsgBreak((uImageFlags & ~VD_IMAGE_FLAGS_MASK) == 0,
     1068                       ("uImageFlags=%#x\n", uImageFlags),
     1069                       rc = VERR_INVALID_PARAMETER);
     1070        AssertMsgBreak(   VALID_PTR(pPCHSGeometry)
     1071                       && pPCHSGeometry->cCylinders <= 16383
     1072                       && pPCHSGeometry->cCylinders != 0
     1073                       && pPCHSGeometry->cHeads <= 16
     1074                       && pPCHSGeometry->cHeads != 0
     1075                       && pPCHSGeometry->cSectors <= 63
     1076                       && pPCHSGeometry->cSectors != 0,
     1077                       ("pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pPCHSGeometry,
     1078                        pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads,
     1079                        pPCHSGeometry->cSectors),
     1080                       rc = VERR_INVALID_PARAMETER);
     1081        AssertMsgBreak(   VALID_PTR(pLCHSGeometry)
     1082                       && pLCHSGeometry->cCylinders <= 16383
     1083                       && pLCHSGeometry->cCylinders != 0
     1084                       && pLCHSGeometry->cHeads <= 16
     1085                       && pLCHSGeometry->cHeads != 0
     1086                       && pLCHSGeometry->cSectors <= 63
     1087                       && pLCHSGeometry->cSectors != 0,
     1088                       ("pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pLCHSGeometry,
     1089                        pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads,
     1090                        pLCHSGeometry->cSectors),
     1091                       rc = VERR_INVALID_PARAMETER);
     1092        AssertMsgBreak((uOpenFlags & ~VD_OPEN_FLAGS_MASK) == 0,
     1093                       ("uOpenFlags=%#x\n", uOpenFlags),
     1094                       rc = VERR_INVALID_PARAMETER);
     1095
     1096        /* Check state. */
     1097        if (pDisk->cImages != 0)
     1098            AssertMsgFailedBreak(("Create base image cannot be done with other images open\n"),
     1099                                 rc = VERR_VDI_INVALID_STATE);
     1100
     1101        /* Set up image descriptor. */
     1102        pImage = (PVDIMAGE)RTMemAllocZ(sizeof(VDIMAGE));
     1103        if (!pImage)
     1104        {
     1105            rc = VERR_NO_MEMORY;
     1106            break;
     1107        }
     1108        pImage->pszFilename = RTStrDup(pszFilename);
     1109        if (!pImage->pszFilename)
     1110        {
     1111            rc = VERR_NO_MEMORY;
     1112            break;
     1113        }
     1114
    9951115        rc = pDisk->Backend->pfnCreate(pImage->pszFilename, enmType, cbSize,
    996                                        uImageFlags, pszComment, cCylinders,
    997                                        cHeads, cSectors, uOpenFlags,
    998                                        pfnProgress, pvUser,
    999                                        pDisk->pfnError, pDisk->pvErrorUser,
     1116                                       uImageFlags, pszComment, pPCHSGeometry,
     1117                                       pLCHSGeometry, uOpenFlags, pfnProgress,
     1118                                       pvUser, 0, 99, pDisk->pfnError,
     1119                                       pDisk->pvErrorUser,
    10001120                                       &pImage->pvBackendData);
    10011121
    1002     if (VBOX_SUCCESS(rc))
    1003     {
    1004         /** @todo optionally check UUIDs */
    1005 
    10061122        if (VBOX_SUCCESS(rc))
    10071123        {
    1008             uint64_t cbSize = pDisk->Backend->pfnGetSize(pImage->pvBackendData);
    1009             if (pDisk->cImages == 0)
     1124            /** @todo optionally check UUIDs */
     1125
     1126            int rc2;
     1127
     1128            /* Cache disk information. */
     1129            pDisk->cbSize = pDisk->Backend->pfnGetSize(pImage->pvBackendData);
     1130
     1131            /* Cache PCHS geometry. */
     1132            rc2 = pDisk->Backend->pfnGetPCHSGeometry(pImage->pvBackendData,
     1133                                                     &pDisk->PCHSGeometry);
     1134            if (VBOX_FAILURE(rc2))
    10101135            {
    1011                 /* Cache disk information. */
    1012                 pDisk->cbSize = cbSize;
    1013 
    1014                 /* Cache CHS geometry. */
    1015                 int rc2 = pDisk->Backend->pfnGetGeometry(pImage->pvBackendData,
    1016                                                          &pDisk->cCylinders,
    1017                                                          &pDisk->cHeads,
    1018                                                          &pDisk->cSectors);
    1019                 if (VBOX_FAILURE(rc2))
    1020                 {
    1021                     pDisk->cCylinders = 0;
    1022                     pDisk->cHeads = 0;
    1023                     pDisk->cSectors = 0;
    1024                 }
    1025                 else
    1026                 {
    1027                     /* Make sure the CHS geometry is properly clipped. */
    1028                     pDisk->cCylinders = RT_MIN(pDisk->cCylinders, 16383);
    1029                     pDisk->cHeads = RT_MIN(pDisk->cHeads, 255);
    1030                     pDisk->cSectors = RT_MIN(pDisk->cSectors, 255);
    1031                 }
    1032 
    1033                 /* Cache translation mode. */
    1034                 rc2 = pDisk->Backend->pfnGetTranslation(pImage->pvBackendData,
    1035                                                         &pDisk->enmTranslation);
    1036                 if (VBOX_FAILURE(rc2))
    1037                     pDisk->enmTranslation = (PDMBIOSTRANSLATION)0;
     1136                pDisk->PCHSGeometry.cCylinders = 0;
     1137                pDisk->PCHSGeometry.cHeads = 0;
     1138                pDisk->PCHSGeometry.cSectors = 0;
    10381139            }
    10391140            else
    10401141            {
    1041                 /* Check image size/block size for consistency. */
    1042                 if (cbSize != pDisk->cbSize)
    1043                     rc = VERR_VDI_INVALID_TYPE;
     1142                /* Make sure the CHS geometry is properly clipped. */
     1143                pDisk->PCHSGeometry.cCylinders = RT_MIN(pDisk->PCHSGeometry.cCylinders, 16383);
     1144                pDisk->PCHSGeometry.cHeads = RT_MIN(pDisk->PCHSGeometry.cHeads, 16);
     1145                pDisk->PCHSGeometry.cSectors = RT_MIN(pDisk->PCHSGeometry.cSectors, 63);
     1146            }
     1147
     1148            /* Cache LCHS geometry. */
     1149            rc2 = pDisk->Backend->pfnGetLCHSGeometry(pImage->pvBackendData,
     1150                                                     &pDisk->LCHSGeometry);
     1151            if (VBOX_FAILURE(rc2))
     1152            {
     1153                pDisk->LCHSGeometry.cCylinders = 0;
     1154                pDisk->LCHSGeometry.cHeads = 0;
     1155                pDisk->LCHSGeometry.cSectors = 0;
     1156            }
     1157            else
     1158            {
     1159                /* Make sure the CHS geometry is properly clipped. */
     1160                pDisk->LCHSGeometry.cCylinders = RT_MIN(pDisk->LCHSGeometry.cCylinders, 1024);
     1161                pDisk->LCHSGeometry.cHeads = RT_MIN(pDisk->LCHSGeometry.cHeads, 255);
     1162                pDisk->LCHSGeometry.cSectors = RT_MIN(pDisk->LCHSGeometry.cSectors, 63);
    10441163            }
    10451164        }
     
    10581177            pImage->pvBackendData = NULL;
    10591178        }
    1060     }
     1179    } while (0);
    10611180
    10621181    if (VBOX_FAILURE(rc))
     
    10701189    }
    10711190
    1072     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     1191    if (VBOX_SUCCESS(rc) && pfnProgress)
     1192        pfnProgress(NULL /* WARNING! pVM=NULL  */, 100, pvUser);
     1193
     1194    LogFlowFunc(("returns %Vrc\n", rc));
    10731195    return rc;
    10741196}
     
    10791201 *
    10801202 * @returns VBox status code.
    1081  * @param   pDisk           Pointer to VBox HDD container.
     1203 * @param   pDisk           Pointer to HDD container.
    10821204 * @param   pszFilename     Name of the differencing image file to create.
    10831205 * @param   uImageFlags     Flags specifying special image features.
     
    10891211VBOXDDU_DECL(int) VDCreateDiff(PVBOXHDD pDisk, const char *pszFilename,
    10901212                               unsigned uImageFlags, const char *pszComment,
    1091                                unsigned uOpenFlags,
    1092                                PFNVMPROGRESS pfnProgress, void *pvUser)
    1093 {
    1094     return VERR_NOT_IMPLEMENTED;
    1095 }
    1096 
    1097 /**
    1098  * Merges two images having a parent/child relationship (both directions).
    1099  * As a side effect the source image is deleted from both the disk and
    1100  * the images in the VBox HDD container.
    1101  *
    1102  * @returns VBox status code.
    1103  * @param   pDisk           Pointer to VBox HDD container.
     1213                               unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
     1214                               void *pvUser)
     1215{
     1216    int rc = VINF_SUCCESS;
     1217    PVDIMAGE pImage = NULL;
     1218
     1219    LogFlowFunc(("pDisk=%#p pszFilename=\"%s\" uImageFlags=%#x pszComment=\"%s\" uOpenFlags=%#x pfnProgress=%#p pvUser=%#p\n",
     1220                 pDisk, pszFilename, uImageFlags, pszComment, uOpenFlags,
     1221                 pfnProgress, pvUser));
     1222    do
     1223    {
     1224        /* sanity check */
     1225        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     1226        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1227
     1228        /* Check arguments. */
     1229        AssertMsgBreak(VALID_PTR(pszFilename) && *pszFilename,
     1230                       ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename),
     1231                       rc = VERR_INVALID_PARAMETER);
     1232        AssertMsgBreak((uImageFlags & ~VD_IMAGE_FLAGS_MASK) == 0,
     1233                       ("uImageFlags=%#x\n", uImageFlags),
     1234                       rc = VERR_INVALID_PARAMETER);
     1235        AssertMsgBreak((uOpenFlags & ~VD_OPEN_FLAGS_MASK) == 0,
     1236                       ("uOpenFlags=%#x\n", uOpenFlags),
     1237                       rc = VERR_INVALID_PARAMETER);
     1238
     1239        /* Check state. */
     1240        if (pDisk->cImages == 0)
     1241            AssertMsgFailedBreak(("Create diff image cannot be done without other images open\n"),
     1242                                 rc = VERR_VDI_INVALID_STATE);
     1243
     1244        /* Set up image descriptor. */
     1245        pImage = (PVDIMAGE)RTMemAllocZ(sizeof(VDIMAGE));
     1246        if (!pImage)
     1247        {
     1248            rc = VERR_NO_MEMORY;
     1249            break;
     1250        }
     1251        pImage->pszFilename = RTStrDup(pszFilename);
     1252        if (!pImage->pszFilename)
     1253        {
     1254            rc = VERR_NO_MEMORY;
     1255            break;
     1256        }
     1257
     1258        rc = pDisk->Backend->pfnCreate(pImage->pszFilename,
     1259                                       VD_IMAGE_TYPE_NORMAL, pDisk->cbSize,
     1260                                       uImageFlags, pszComment,
     1261                                       &pDisk->PCHSGeometry,
     1262                                       &pDisk->LCHSGeometry, uOpenFlags,
     1263                                       pfnProgress, pvUser, 0, 99,
     1264                                       pDisk->pfnError, pDisk->pvErrorUser,
     1265                                       &pImage->pvBackendData);
     1266
     1267        if (VBOX_SUCCESS(rc))
     1268        {
     1269            /** @todo optionally check UUIDs */
     1270        }
     1271
     1272        if (VBOX_SUCCESS(rc))
     1273        {
     1274            /* Image successfully opened, make it the last image. */
     1275            vdAddImageToList(pDisk, pImage);
     1276        }
     1277        else
     1278        {
     1279            /* Error detected, but image opened. Close and delete image. */
     1280            int rc2;
     1281            rc2 = pDisk->Backend->pfnClose(pImage->pvBackendData, true);
     1282            AssertRC(rc2);
     1283            pImage->pvBackendData = NULL;
     1284        }
     1285    } while (0);
     1286
     1287    if (VBOX_FAILURE(rc))
     1288    {
     1289        if (pImage)
     1290        {
     1291            if (pImage->pszFilename)
     1292                RTStrFree(pImage->pszFilename);
     1293            RTMemFree(pImage);
     1294        }
     1295    }
     1296
     1297    if (VBOX_SUCCESS(rc) && pfnProgress)
     1298        pfnProgress(NULL /* WARNING! pVM=NULL  */, 100, pvUser);
     1299
     1300    LogFlowFunc(("returns %Vrc\n", rc));
     1301    return rc;
     1302}
     1303
     1304/**
     1305 * Merges two images (not necessarily with direct parent/child relationship).
     1306 * As a side effect the source image and potentially the other images which
     1307 * are also merged to the destination are deleted from both the disk and the
     1308 * images in the HDD container.
     1309 *
     1310 * @returns VBox status code.
     1311 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     1312 * @param   pDisk           Pointer to HDD container.
    11041313 * @param   nImageFrom      Name of the image file to merge from.
    11051314 * @param   nImageTo        Name of the image file to merge to.
     
    11111320                          void *pvUser)
    11121321{
    1113     return VERR_NOT_IMPLEMENTED;
    1114 }
    1115 
    1116 /**
    1117  * Copies an image from one VBox HDD container to another.
    1118  * The copy is opened in the target VBox HDD container.
     1322    int rc = VINF_SUCCESS;
     1323    void *pvBuf = NULL;
     1324
     1325    LogFlowFunc(("pDisk=%#p nImageFrom=%u nImageTo=%u pfnProgress=%#p pvUser=%#p\n",
     1326                 pDisk, nImageFrom, nImageTo, pfnProgress, pvUser));
     1327    do
     1328    {
     1329        /* sanity check */
     1330        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     1331        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1332
     1333        PVDIMAGE pImageFrom = vdGetImageByNumber(pDisk, nImageFrom);
     1334        PVDIMAGE pImageTo = vdGetImageByNumber(pDisk, nImageTo);
     1335        if (!pImageFrom || !pImageTo)
     1336        {
     1337            rc = VERR_VDI_IMAGE_NOT_FOUND;
     1338            break;
     1339        }
     1340        AssertBreak(pImageFrom != pImageTo, rc = VERR_INVALID_PARAMETER);
     1341
     1342        /* Check if destination image is writable. */
     1343        unsigned uOpenFlags = pDisk->Backend->pfnGetOpenFlags(pImageTo->pvBackendData);
     1344        if (uOpenFlags & VD_OPEN_FLAGS_READONLY)
     1345        {
     1346            rc = VERR_VDI_IMAGE_READ_ONLY;
     1347            break;
     1348        }
     1349
     1350        /* Get size of destination image. */
     1351        uint64_t cbSize = pDisk->Backend->pfnGetSize(pImageTo->pvBackendData);
     1352
     1353        /* Allocate tmp buffer. */
     1354        pvBuf = RTMemTmpAlloc(VD_MERGE_BUFFER_SIZE);
     1355        if (!pvBuf)
     1356        {
     1357            rc = VERR_NO_MEMORY;
     1358            break;
     1359        }
     1360
     1361        /* Merging is done directly on the images itself. This potentially
     1362         * causes trouble if the disk is full in the middle of operation. */
     1363        /** @todo write alternative implementation which works with temporary
     1364         * images (which is safer, but requires even more space). Also has the
     1365         * drawback that merging into a raw disk parent simply isn't possible
     1366         * this way (but in that case disk full isn't really a problem). */
     1367        if (nImageFrom < nImageTo)
     1368        {
     1369            /* Merge parent state into child. This means writing all not
     1370             * allocated blocks in the destination image which are allocated in
     1371             * the images to be merged. */
     1372            uint64_t uOffset = 0;
     1373            uint64_t cbRemaining = cbSize;
     1374            do
     1375            {
     1376                size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining);
     1377                rc = pDisk->Backend->pfnRead(pImageTo->pvBackendData, uOffset,
     1378                                             pvBuf, cbThisRead, &cbThisRead);
     1379                if (VBOX_FAILURE(rc))
     1380                    break;
     1381                if (rc == VINF_VDI_BLOCK_FREE)
     1382                {
     1383                    /* Search for image with allocated block. Do not attempt to
     1384                     * read more than the previous reads marked as valid.
     1385                     * Otherwise this would return stale data when different
     1386                     * block sizes are used for the images. */
     1387                    for (PVDIMAGE pCurrImage = pImageTo->pPrev;
     1388                         pCurrImage != NULL && pCurrImage != pImageFrom->pPrev && rc == VINF_VDI_BLOCK_FREE;
     1389                         pCurrImage = pCurrImage->pPrev)
     1390                    {
     1391                        rc = pDisk->Backend->pfnRead(pCurrImage->pvBackendData,
     1392                                                     uOffset, pvBuf,
     1393                                                     cbThisRead, &cbThisRead);
     1394                    }
     1395                    if (VBOX_FAILURE(rc))
     1396                        break;
     1397
     1398                    if (rc != VINF_VDI_BLOCK_FREE)
     1399                    {
     1400                        rc = vdWriteHelper(pDisk, pImageTo, uOffset, pvBuf,
     1401                                           cbThisRead);
     1402                        if (VBOX_FAILURE(rc))
     1403                            break;
     1404                    }
     1405                }
     1406
     1407                uOffset += cbThisRead;
     1408                cbRemaining -= cbThisRead;
     1409            } while (uOffset < cbSize);
     1410        }
     1411        else
     1412        {
     1413            /* Merge child state into parent. This means writing all blocks
     1414             * which are allocated in the image up to the source image to the
     1415             * destination image. */
     1416            uint64_t uOffset = 0;
     1417            uint64_t cbRemaining = cbSize;
     1418            do
     1419            {
     1420                size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining);
     1421                /* Search for image with allocated block. Do not attempt to
     1422                 * read more than the previous reads marked as valid. Otherwise
     1423                 * this would return stale data when different block sizes are
     1424                 * used for the images. */
     1425                for (PVDIMAGE pCurrImage = pImageFrom;
     1426                     pCurrImage != NULL && pCurrImage != pImageTo && rc == VINF_VDI_BLOCK_FREE;
     1427                     pCurrImage = pCurrImage->pPrev)
     1428                {
     1429                    rc = pDisk->Backend->pfnRead(pCurrImage->pvBackendData,
     1430                                                 uOffset, pvBuf,
     1431                                                 cbThisRead, &cbThisRead);
     1432                }
     1433                if (VBOX_FAILURE(rc))
     1434                    break;
     1435
     1436                if (rc != VINF_VDI_BLOCK_FREE)
     1437                {
     1438                    rc = vdWriteHelper(pDisk, pImageTo, uOffset, pvBuf,
     1439                                       cbThisRead);
     1440                    if (VBOX_FAILURE(rc))
     1441                        break;
     1442                }
     1443
     1444                uOffset += cbThisRead;
     1445                cbRemaining -= cbThisRead;
     1446            } while (uOffset < cbSize);
     1447        }
     1448
     1449        /* Update parent UUID so that image chain is consistent. */
     1450        RTUUID Uuid;
     1451        if (nImageFrom < nImageTo)
     1452        {
     1453            if (pImageTo->pPrev)
     1454            {
     1455                rc = pDisk->Backend->pfnGetUuid(pImageTo->pPrev->pvBackendData,
     1456                                                &Uuid);
     1457                AssertRC(rc);
     1458            }
     1459            else
     1460                RTUuidClear(&Uuid);
     1461            rc = pDisk->Backend->pfnSetParentUuid(pImageTo->pvBackendData,
     1462                                                  &Uuid);
     1463            AssertRC(rc);
     1464        }
     1465        else
     1466        {
     1467            if (pImageFrom->pNext)
     1468            {
     1469                rc = pDisk->Backend->pfnGetUuid(pImageTo->pvBackendData,
     1470                                                &Uuid);
     1471                AssertRC(rc);
     1472                rc = pDisk->Backend->pfnSetParentUuid(pImageFrom->pNext,
     1473                                                      &Uuid);
     1474                AssertRC(rc);
     1475            }
     1476        }
     1477
     1478        /* Delete the no longer needed images. */
     1479        PVDIMAGE pImg = pImageFrom, pTmp;
     1480        while (pImg != pImageTo)
     1481        {
     1482            if (nImageFrom < nImageTo)
     1483                pTmp = pImg->pNext;
     1484            else
     1485                pTmp = pImg->pPrev;
     1486            vdRemoveImageFromList(pDisk, pImg);
     1487            pDisk->Backend->pfnClose(pImg->pvBackendData, true);
     1488            pImg = pTmp;
     1489        }
     1490    } while (0);
     1491
     1492    if (pvBuf)
     1493        RTMemTmpFree(pvBuf);
     1494
     1495    if (VBOX_SUCCESS(rc) && pfnProgress)
     1496        pfnProgress(NULL /* WARNING! pVM=NULL */, 100, pvUser);
     1497
     1498    LogFlowFunc(("returns %Vrc\n", rc));
     1499    return rc;
     1500}
     1501
     1502/**
     1503 * Copies an image from one HDD container to another.
     1504 * The copy is opened in the target HDD container.
    11191505 * It is possible to convert between different image formats, because the
    1120  * backend for the destination VBox HDD container may be different from the
     1506 * backend for the destination HDD container may be different from the
    11211507 * source container.
    1122  * If both the source and destination reference the same VBox HDD container,
    1123  * then the image is moved (by copying/deleting) to the new location.
     1508 * If both the source and destination reference the same HDD container,
     1509 * then the image is moved (by copying/deleting or renaming) to the new location.
    11241510 * The source container is unchanged if the move operation fails, otherwise
    11251511 * the image at the new location is opened in the same way as the old one was.
    11261512 *
    11271513 * @returns VBox status code.
    1128  * @param   pDiskFrom       Pointer to source VBox HDD container.
     1514 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     1515 * @param   pDiskFrom       Pointer to source HDD container.
    11291516 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    1130  * @param   pDiskTo         Pointer to destination VBox HDD container.
     1517 * @param   pDiskTo         Pointer to destination HDD container.
     1518 * @param   pszFilename     New name of the image (may be NULL if pDiskFrom == pDiskTo).
     1519 * @param   fMoveByRename   If true, attempt to perform a move by renaming (if successful the new size is ignored).
     1520 * @param   cbSize          New image size (0 means leave unchanged).
    11311521 * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
    11321522 * @param   pvUser          User argument for the progress callback.
    11331523 */
    11341524VBOXDDU_DECL(int) VDCopy(PVBOXHDD pDiskFrom, unsigned nImage, PVBOXHDD pDiskTo,
    1135                          PFNVMPROGRESS pfnProgress, void *pvUser)
     1525                         const char *pszFilename, bool fMoveByRename,
     1526                         uint64_t cbSize, PFNVMPROGRESS pfnProgress,
     1527                         void *pvUser)
    11361528{
    11371529    return VERR_NOT_IMPLEMENTED;
     
    11391531
    11401532/**
    1141  * Compacts a growing image file by removing zeroed data blocks.
    1142  * Optionally defragments data in the image so that ascending sector numbers
    1143  * are stored in ascending location in the image file.
    1144  *
    1145  * @todo maybe include this function in VDCopy.
    1146  *
    1147  * @returns VBox status code.
    1148  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    1149  * @param   pDisk           Pointer to VBox HDD container.
    1150  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    1151  * @param   fDefragment     If true, reorder file data so that sectors are stored in ascending order.
    1152  * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
    1153  * @param   pvUser          User argument for the progress callback.
    1154  */
    1155 VBOXDDU_DECL(int) VDCompact(PVBOXHDD pDisk, unsigned nImage,
    1156                             bool fDefragment,
    1157                             PFNVMPROGRESS pfnProgress, void *pvUser)
    1158 {
    1159     return VERR_NOT_IMPLEMENTED;
    1160 }
    1161 
    1162 /**
    1163  * Resizes an image. Allows setting the disk size to both larger and smaller
    1164  * values than the current disk size.
    1165  *
    1166  * @returns VBox status code.
    1167  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    1168  * @param   pDisk           Pointer to VBox HDD container.
    1169  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    1170  * @param   cbSize          New image size in bytes.
    1171  * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
    1172  * @param   pvUser          User argument for the progress callback.
    1173  */
    1174 VBOXDDU_DECL(int) VDResize(PVBOXHDD pDisk, unsigned nImage, uint64_t cbSize,
    1175                            PFNVMPROGRESS pfnProgress, void *pvUser)
    1176 {
    1177     return VERR_NOT_IMPLEMENTED;
    1178 }
    1179 
    1180 /**
    1181  * Closes the last opened image file in the HDD container. Leaves all changes inside it.
     1533 * Closes the last opened image file in HDD container.
    11821534 * If previous image file was opened in read-only mode (that is normal) and closing image
    11831535 * was opened in read-write mode (the whole disk was in read-write mode) - the previous image
    11841536 * will be reopened in read/write mode.
    11851537 *
    1186  * @param   pDisk           Pointer to VBox HDD container.
     1538 * @returns VBox status code.
     1539 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     1540 * @param   pDisk           Pointer to HDD container.
    11871541 * @param   fDelete         If true, delete the image from the host disk.
    11881542 */
    11891543VBOXDDU_DECL(int) VDClose(PVBOXHDD pDisk, bool fDelete)
    11901544{
    1191     LogFlow(("%s: fDelete=%d\n", __FUNCTION__, fDelete));
    1192     /* sanity check */
    1193     Assert(pDisk);
    1194     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1195 
    1196     PVDIMAGE pImage = pDisk->pLast;
    1197     unsigned uOpenFlags = pDisk->Backend->pfnGetOpenFlags(pImage->pvBackendData);
    1198     /* Remove image from list of opened images. */
    1199     vdRemoveImageFromList(pDisk, pImage);
    1200     /* Close (and optionally delete) image. */
    1201     int rc = pDisk->Backend->pfnClose(pImage->pvBackendData, fDelete);
    1202     /* Free remaining resources related to the image. */
    1203     RTStrFree(pImage->pszFilename);
    1204     RTMemFree(pImage);
    1205 
    1206     /* If disk was previously in read/write mode, make sure it will stay like
    1207      * this after closing this image. Set the open flags accordingly. */
    1208     if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
    1209     {
    1210         uOpenFlags = pDisk->Backend->pfnGetOpenFlags(pDisk->pLast->pvBackendData);
    1211         uOpenFlags &= ~ VD_OPEN_FLAGS_READONLY;
    1212         rc = pDisk->Backend->pfnSetOpenFlags(pDisk->pLast->pvBackendData,
    1213                                                      uOpenFlags);
    1214     }
    1215 
    1216     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    1217     return rc;
    1218 }
    1219 
    1220 /**
    1221  * Closes all opened image files in HDD container.
    1222  *
    1223  * @param   pDisk           Pointer to VDI HDD container.
    1224  */
    1225 VBOXDDU_DECL(int) VDCloseAll(PVBOXHDD pDisk)
    1226 {
    1227     LogFlow(("%s:\n", __FUNCTION__));
    1228     /* sanity check */
    1229     Assert(pDisk);
    1230     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1231 
    1232     PVDIMAGE pImage = pDisk->pLast;
    1233     int rc = VINF_SUCCESS;
    1234     while (pImage)
    1235     {
    1236         PVDIMAGE pPrev = pImage->pPrev;
     1545    int rc = VINF_SUCCESS;;
     1546
     1547    LogFlowFunc(("fDelete=%d\n", fDelete));
     1548    do
     1549    {
     1550        /* sanity check */
     1551        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     1552        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1553
     1554        PVDIMAGE pImage = pDisk->pLast;
     1555        if (RT_UNLIKELY(!pImage))
     1556        {
     1557            Assert(pImage);
     1558            rc = VERR_VDI_NOT_OPENED;
     1559            break;
     1560        }
     1561        unsigned uOpenFlags = pDisk->Backend->pfnGetOpenFlags(pImage->pvBackendData);
    12371562        /* Remove image from list of opened images. */
    12381563        vdRemoveImageFromList(pDisk, pImage);
    1239         /* Close image. */
    1240         int rc2 = pDisk->Backend->pfnClose(pImage->pvBackendData, false);
    1241         if (VBOX_FAILURE(rc2) && VBOX_SUCCESS(rc))
    1242             rc = rc2;
     1564        /* Close (and optionally delete) image. */
     1565        rc = pDisk->Backend->pfnClose(pImage->pvBackendData, fDelete);
    12431566        /* Free remaining resources related to the image. */
    12441567        RTStrFree(pImage->pszFilename);
    12451568        RTMemFree(pImage);
    1246         pImage = pPrev;
    1247     }
    1248     Assert(pDisk->pLast == NULL);
    1249 
    1250     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     1569
     1570        pImage = pDisk->pLast;
     1571        if (!pImage)
     1572            break;
     1573
     1574        /* If disk was previously in read/write mode, make sure it will stay
     1575         * like this (if possible) after closing this image. Set the open flags
     1576         * accordingly. */
     1577        if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
     1578        {
     1579            uOpenFlags = pDisk->Backend->pfnGetOpenFlags(pImage->pvBackendData);
     1580            uOpenFlags &= ~ VD_OPEN_FLAGS_READONLY;
     1581            rc = pDisk->Backend->pfnSetOpenFlags(pImage->pvBackendData, uOpenFlags);
     1582        }
     1583
     1584        int rc2;
     1585
     1586        /* Cache disk information. */
     1587        pDisk->cbSize = pDisk->Backend->pfnGetSize(pImage->pvBackendData);
     1588
     1589        /* Cache PCHS geometry. */
     1590        rc2 = pDisk->Backend->pfnGetPCHSGeometry(pImage->pvBackendData,
     1591                                                 &pDisk->PCHSGeometry);
     1592        if (VBOX_FAILURE(rc2))
     1593        {
     1594            pDisk->PCHSGeometry.cCylinders = 0;
     1595            pDisk->PCHSGeometry.cHeads = 0;
     1596            pDisk->PCHSGeometry.cSectors = 0;
     1597        }
     1598        else
     1599        {
     1600            /* Make sure the PCHS geometry is properly clipped. */
     1601            pDisk->PCHSGeometry.cCylinders = RT_MIN(pDisk->PCHSGeometry.cCylinders, 16383);
     1602            pDisk->PCHSGeometry.cHeads = RT_MIN(pDisk->PCHSGeometry.cHeads, 16);
     1603            pDisk->PCHSGeometry.cSectors = RT_MIN(pDisk->PCHSGeometry.cSectors, 63);
     1604        }
     1605
     1606        /* Cache LCHS geometry. */
     1607        rc2 = pDisk->Backend->pfnGetLCHSGeometry(pImage->pvBackendData,
     1608                                                 &pDisk->LCHSGeometry);
     1609        if (VBOX_FAILURE(rc2))
     1610        {
     1611            pDisk->LCHSGeometry.cCylinders = 0;
     1612            pDisk->LCHSGeometry.cHeads = 0;
     1613            pDisk->LCHSGeometry.cSectors = 0;
     1614        }
     1615        else
     1616        {
     1617            /* Make sure the LCHS geometry is properly clipped. */
     1618            pDisk->LCHSGeometry.cCylinders = RT_MIN(pDisk->LCHSGeometry.cCylinders, 1024);
     1619            pDisk->LCHSGeometry.cHeads = RT_MIN(pDisk->LCHSGeometry.cHeads, 255);
     1620            pDisk->LCHSGeometry.cSectors = RT_MIN(pDisk->LCHSGeometry.cSectors, 63);
     1621        }
     1622    } while (0);
     1623
     1624    LogFlowFunc(("returns %Vrc\n", rc));
     1625    return rc;
     1626}
     1627
     1628/**
     1629 * Closes all opened image files in HDD container.
     1630 *
     1631 * @returns VBox status code.
     1632 * @param   pDisk           Pointer to HDD container.
     1633 */
     1634VBOXDDU_DECL(int) VDCloseAll(PVBOXHDD pDisk)
     1635{
     1636    int rc = VINF_SUCCESS;
     1637
     1638    LogFlowFunc(("pDisk=%#p\n", pDisk));
     1639    do
     1640    {
     1641        /* sanity check */
     1642        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     1643        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1644
     1645        PVDIMAGE pImage = pDisk->pLast;
     1646        while (pImage)
     1647        {
     1648            PVDIMAGE pPrev = pImage->pPrev;
     1649            /* Remove image from list of opened images. */
     1650            vdRemoveImageFromList(pDisk, pImage);
     1651            /* Close image. */
     1652            int rc2 = pDisk->Backend->pfnClose(pImage->pvBackendData, false);
     1653            if (VBOX_FAILURE(rc2) && VBOX_SUCCESS(rc))
     1654                rc = rc2;
     1655            /* Free remaining resources related to the image. */
     1656            RTStrFree(pImage->pszFilename);
     1657            RTMemFree(pImage);
     1658            pImage = pPrev;
     1659        }
     1660        Assert(pDisk->pLast == NULL);
     1661    } while (0);
     1662
     1663    LogFlowFunc(("returns %Vrc\n", rc));
    12511664    return rc;
    12521665}
     
    12561669 *
    12571670 * @returns VBox status code.
    1258  * @param   pDisk           Pointer to VBox HDD container.
     1671 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     1672 * @param   pDisk           Pointer to HDD container.
    12591673 * @param   uOffset         Offset of first reading byte from start of disk.
    12601674 * @param   pvBuf           Pointer to buffer for reading data.
    12611675 * @param   cbRead          Number of bytes to read.
    12621676 */
    1263 VBOXDDU_DECL(int) VDRead(PVBOXHDD pDisk, uint64_t uOffset, void *pvBuf, size_t cbRead)
    1264 {
    1265     /* sanity check */
    1266     LogFlow(("%s: offset=%llu cbRead=%u\n", __FUNCTION__, uOffset, (unsigned)cbRead));
    1267     Assert(pDisk);
    1268     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1269 
    1270     int rc = VINF_SUCCESS;
    1271     PVDIMAGE pImage = pDisk->pLast;
    1272     if (RT_UNLIKELY(!pImage))
    1273     {
    1274         Assert(pImage);
    1275         rc = VERR_VDI_NOT_OPENED;
    1276         goto out;
    1277     }
    1278 
    1279     /* Check params. */
    1280     if (uOffset + cbRead > pDisk->cbSize || cbRead == 0)
    1281     {
    1282         AssertMsgFailed(("uOffset=%llu cbRead=%u\n", uOffset, cbRead));
    1283         return VERR_INVALID_PARAMETER;
    1284     }
    1285 
    1286     rc = vdReadHelper(pDisk, pImage, uOffset, pvBuf, cbRead);
    1287 out:
    1288     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     1677VBOXDDU_DECL(int) VDRead(PVBOXHDD pDisk, uint64_t uOffset, void *pvBuf,
     1678                         size_t cbRead)
     1679{
     1680    int rc;
     1681
     1682    LogFlowFunc(("pDisk=%#p uOffset=%llu pvBuf=%p cbRead=%llu\n",
     1683                 pDisk, uOffset, pvBuf, cbRead));
     1684    do
     1685    {
     1686        /* sanity check */
     1687        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     1688        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1689
     1690        /* Check arguments. */
     1691        AssertMsgBreak(VALID_PTR(pvBuf),
     1692                       ("pvBuf=%#p\n", pvBuf),
     1693                       rc = VERR_INVALID_PARAMETER);
     1694        AssertMsgBreak(cbRead,
     1695                       ("cbRead=%llu\n", cbRead),
     1696                       rc = VERR_INVALID_PARAMETER);
     1697        AssertMsgBreak(uOffset + cbRead > pDisk->cbSize,
     1698                       ("uOffset=%llu cbRead=%llu pDisk->cbSize=%llu\n",
     1699                        uOffset, cbRead, pDisk->cbSize),
     1700                       rc = VERR_INVALID_PARAMETER);
     1701
     1702        PVDIMAGE pImage = pDisk->pLast;
     1703        AssertBreak(pImage, rc = VERR_VDI_NOT_OPENED);
     1704
     1705        rc = vdReadHelper(pDisk, pImage, uOffset, pvBuf, cbRead);
     1706    } while (0);
     1707
     1708    LogFlowFunc(("returns %Vrc\n", rc));
    12891709    return rc;
    12901710}
     
    12941714 *
    12951715 * @returns VBox status code.
    1296  * @param   pDisk           Pointer to VBox HDD container.
     1716 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     1717 * @param   pDisk           Pointer to HDD container.
    12971718 * @param   uOffset         Offset of first reading byte from start of disk.
    12981719 * @param   pvBuf           Pointer to buffer for writing data.
     
    13011722VBOXDDU_DECL(int) VDWrite(PVBOXHDD pDisk, uint64_t uOffset, const void *pvBuf, size_t cbWrite)
    13021723{
    1303     /* sanity check */
    1304     Assert(pDisk);
    1305     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1306 
    13071724    int rc = VINF_SUCCESS;
    1308     size_t cbThisWrite;
    1309     size_t cbPreRead, cbPostRead;
    1310     PVDIMAGE pImage = pDisk->pLast;
    1311     if (RT_UNLIKELY(!pImage))
    1312     {
    1313         Assert(pImage);
    1314         rc = VERR_VDI_NOT_OPENED;
    1315         goto out;
    1316     }
    1317 
    1318     /* Check params. */
    1319     if (uOffset + cbWrite > pDisk->cbSize || cbWrite == 0)
    1320     {
    1321         AssertMsgFailed(("uOffset=%llu cbWrite=%u\n", uOffset, cbWrite));
    1322         rc = VERR_INVALID_PARAMETER;
    1323         goto out;
    1324     }
    1325 
    1326     vdSetModifiedFlag(pDisk);
    1327 
    1328     /* Loop until all written. */
    1329     do
    1330     {
    1331         /* Try to write the possibly partial block to the last opened image.
    1332          * This works when the block is already allocated in this image or
    1333          * if it is a full-block write, which automatically allocates a new
    1334          * block if needed. */
    1335         cbThisWrite = cbWrite;
    1336         rc = pDisk->Backend->pfnWrite(pImage->pvBackendData, uOffset, pvBuf,
    1337                                       cbThisWrite, &cbThisWrite,
    1338                                       &cbPreRead, &cbPostRead);
    1339         if (rc == VINF_VDI_BLOCK_FREE)
    1340         {
    1341             void *pvTmp = RTMemTmpAlloc(cbPreRead + cbThisWrite + cbPostRead);
    1342             if (!pvBuf)
    1343             {
    1344                 Assert(!pvBuf);
    1345                 rc = VERR_NO_MEMORY;
    1346                 break;
    1347             }
    1348 
    1349             if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME))
    1350             {
    1351                 /* Optimized write, suppress writing to a so far unallocated
    1352                  * block when the data is identical than as of the parent. */
    1353                 rc = vdWriteHelperOptimized(pDisk, pImage, uOffset,
    1354                                             cbWrite, cbThisWrite,
    1355                                             cbPreRead, cbPostRead,
    1356                                             pvBuf, pvTmp);
    1357             }
    1358             else
    1359             {
    1360                 /* Normal write, not optimized in any way. The block will be
    1361                  * written no matter what. This will usually (unless the
    1362                  * backend has some further optimization enabled) cause the
    1363                  * block to be allocated. */
    1364                 rc = vdWriteHelperStandard(pDisk, pImage, uOffset,
    1365                                            cbWrite, cbThisWrite,
    1366                                            cbPreRead, cbPostRead,
    1367                                            pvBuf, pvTmp);
    1368             }
    1369             RTMemTmpFree(pvTmp);
    1370             if (VBOX_FAILURE(rc))
    1371                 break;
    1372         }
    1373 
    1374         cbWrite -= cbThisWrite;
    1375         uOffset += cbThisWrite;
    1376         pvBuf = (char *)pvBuf + cbThisWrite;
    1377     } while (cbWrite != 0 && VBOX_SUCCESS(rc));
    1378 
    1379 out:
    1380     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     1725
     1726    LogFlowFunc(("pDisk=%#p uOffset=%llu pvBuf=%p cbWrite=%llu\n",
     1727                 pDisk, uOffset, pvBuf, cbWrite));
     1728    do
     1729    {
     1730        /* sanity check */
     1731        AssertBreak(VALID_PTR(pDisk), VERR_INVALID_PARAMETER);
     1732        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1733
     1734        /* Check arguments. */
     1735        AssertMsgBreak(VALID_PTR(pvBuf),
     1736                       ("pvBuf=%#p\n", pvBuf),
     1737                       rc = VERR_INVALID_PARAMETER);
     1738        AssertMsgBreak(cbWrite,
     1739                       ("cbWrite=%llu\n", cbWrite),
     1740                       rc = VERR_INVALID_PARAMETER);
     1741        AssertMsgBreak(uOffset + cbWrite > pDisk->cbSize,
     1742                       ("uOffset=%llu cbWrite=%llu pDisk->cbSize=%llu\n",
     1743                        uOffset, cbWrite, pDisk->cbSize),
     1744                       rc = VERR_INVALID_PARAMETER);
     1745
     1746        PVDIMAGE pImage = pDisk->pLast;
     1747        AssertBreak(pImage, rc = VERR_VDI_NOT_OPENED);
     1748
     1749        vdSetModifiedFlag(pDisk);
     1750        rc = vdWriteHelper(pDisk, pImage, uOffset, pvBuf, cbWrite);
     1751    } while (0);
     1752
     1753    LogFlowFunc(("returns %Vrc\n", rc));
    13811754    return rc;
    13821755}
     
    13861759 *
    13871760 * @returns VBox status code.
    1388  * @param   pDisk           Pointer to VBox HDD container.
     1761 * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     1762 * @param   pDisk           Pointer to HDD container.
    13891763 */
    13901764VBOXDDU_DECL(int) VDFlush(PVBOXHDD pDisk)
    13911765{
    1392     /* sanity check */
    1393     Assert(pDisk);
    1394     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1395 
    13961766    int rc = VINF_SUCCESS;
    1397     PVDIMAGE pImage = pDisk->pLast;
    1398     if (RT_UNLIKELY(!pImage))
    1399     {
    1400         Assert(pImage);
    1401         rc = VERR_VDI_NOT_OPENED;
    1402     }
    1403     else
    1404     {
     1767
     1768    LogFlowFunc(("pDisk=%#p\n", pDisk));
     1769    do
     1770    {
     1771        /* sanity check */
     1772        AssertBreak(VALID_PTR(pDisk), VERR_INVALID_PARAMETER);
     1773        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1774
     1775        PVDIMAGE pImage = pDisk->pLast;
     1776        AssertBreak(pImage, rc = VERR_VDI_NOT_OPENED);
     1777
    14051778        vdResetModifiedFlag(pDisk);
    14061779        rc = pDisk->Backend->pfnFlush(pImage->pvBackendData);
    1407     }
    1408 
    1409     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     1780    } while (0);
     1781
     1782    LogFlowFunc(("returns %Vrc\n", rc));
    14101783    return rc;
    14111784}
     
    14151788 *
    14161789 * @returns Number of opened images for HDD container. 0 if no images have been opened.
    1417  * @param   pDisk           Pointer to VBox HDD container.
     1790 * @param   pDisk           Pointer to HDD container.
    14181791 */
    14191792VBOXDDU_DECL(unsigned) VDGetCount(PVBOXHDD pDisk)
    14201793{
    1421     /* sanity check */
    1422     Assert(pDisk);
    1423     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1424 
    1425     unsigned c = pDisk->cImages;
    1426     LogFlow(("%s: returns %d\n", __FUNCTION__, c));
    1427     return c;
    1428 }
    1429 
    1430 /**
    1431  * Get read/write mode of the VBox HDD container.
     1794    unsigned cImages;
     1795
     1796    LogFlowFunc(("pDisk=%#p\n", pDisk));
     1797    do
     1798    {
     1799        /* sanity check */
     1800        AssertBreak(VALID_PTR(pDisk), cImages = 0);
     1801        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1802
     1803        cImages = pDisk->cImages;
     1804    } while (0);
     1805
     1806    LogFlowFunc(("returns %u\n", cImages));
     1807    return cImages;
     1808}
     1809
     1810/**
     1811 * Get read/write mode of HDD container.
    14321812 *
    14331813 * @returns Virtual disk ReadOnly status.
    14341814 * @returns true if no image is opened in HDD container.
    1435  * @param   pDisk           Pointer to VBox HDD container.
     1815 * @param   pDisk           Pointer to HDD container.
    14361816 */
    14371817VBOXDDU_DECL(bool) VDIsReadOnly(PVBOXHDD pDisk)
    14381818{
    1439     /* sanity check */
    1440     Assert(pDisk);
    1441     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1442 
    1443     bool f;
    1444     if (pDisk->pLast)
    1445     {
     1819    bool fReadOnly;
     1820
     1821    LogFlowFunc(("pDisk=%#p\n", pDisk));
     1822    do
     1823    {
     1824        /* sanity check */
     1825        AssertBreak(VALID_PTR(pDisk), fReadOnly = false);
     1826        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1827
     1828        PVDIMAGE pImage = pDisk->pLast;
     1829        AssertBreak(pImage, fReadOnly = true);
     1830
    14461831        unsigned uOpenFlags;
    14471832        uOpenFlags = pDisk->Backend->pfnGetOpenFlags(pDisk->pLast->pvBackendData);
    1448         f = !!(uOpenFlags & VD_OPEN_FLAGS_READONLY);
    1449     }
    1450     else
    1451     {
    1452         AssertMsgFailed(("No disk image is opened!\n"));
    1453         f = true;
    1454     }
    1455 
    1456     LogFlow(("%s: returns %d\n", __FUNCTION__, f));
    1457     return f;
    1458 }
    1459 
    1460 /**
    1461  * Get total disk size of the VBox HDD container.
     1833        fReadOnly = !!(uOpenFlags & VD_OPEN_FLAGS_READONLY);
     1834    } while (0);
     1835
     1836    LogFlowFunc(("returns %d\n", fReadOnly));
     1837    return fReadOnly;
     1838}
     1839
     1840/**
     1841 * Get total capacity of an image in HDD container.
     1842 *
     1843 * @returns Virtual disk size in bytes.
     1844 * @returns 0 if no image with specified number was not opened.
     1845 * @param   pDisk           Pointer to HDD container.
     1846 * @param   nImage          Image number, counds from 0. 0 is always base image of container.
     1847 */
     1848VBOXDDU_DECL(uint64_t) VDGetSize(PVBOXHDD pDisk, unsigned nImage)
     1849{
     1850    uint64_t cbSize;
     1851
     1852    LogFlowFunc(("pDisk=%#p nImage=%u\n", pDisk, nImage));
     1853    do
     1854    {
     1855        /* sanity check */
     1856        AssertBreak(VALID_PTR(pDisk), cbSize = 0);
     1857        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1858
     1859        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     1860        AssertBreak(pImage, cbSize = 0);
     1861        cbSize = pDisk->Backend->pfnGetSize(pImage->pvBackendData);
     1862    } while (0);
     1863
     1864    LogFlowFunc(("returns %llu\n", cbSize));
     1865    return cbSize;
     1866}
     1867
     1868/**
     1869 * Get total file size of an image in HDD container.
    14621870 *
    14631871 * @returns Virtual disk size in bytes.
    14641872 * @returns 0 if no image is opened in HDD container.
    1465  * @param   pDisk           Pointer to VBox HDD container.
    1466  */
    1467 VBOXDDU_DECL(uint64_t) VDGetSize(PVBOXHDD pDisk)
    1468 {
    1469     /* sanity check */
    1470     Assert(pDisk);
    1471     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1472 
    1473     uint64_t cb = pDisk->cbSize;
    1474     LogFlow(("%s: returns %lld\n", __FUNCTION__, cb));
    1475     return cb;
    1476 }
    1477 
    1478 /**
    1479  * Get virtual disk geometry stored in HDD container.
    1480  *
    1481  * @returns VBox status code.
    1482  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
     1873 * @param   pDisk           Pointer to HDD container.
     1874 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     1875 */
     1876VBOXDDU_DECL(uint64_t) VDGetFileSize(PVBOXHDD pDisk, unsigned nImage)
     1877{
     1878    uint64_t cbSize;
     1879
     1880    LogFlowFunc(("pDisk=%#p nImage=%u\n", pDisk, nImage));
     1881    do
     1882    {
     1883        /* sanity check */
     1884        AssertBreak(VALID_PTR(pDisk), cbSize = 0);
     1885        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1886
     1887        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     1888        AssertBreak(pImage, cbSize = 0);
     1889        cbSize = pDisk->Backend->pfnGetFileSize(pImage->pvBackendData);
     1890    } while (0);
     1891
     1892    LogFlowFunc(("returns %llu\n", cbSize));
     1893    return cbSize;
     1894}
     1895
     1896/**
     1897 * Get virtual disk PCHS geometry stored in HDD container.
     1898 *
     1899 * @returns VBox status code.
     1900 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    14831901 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
    1484  * @param   pDisk           Pointer to VBox HDD container.
    1485  * @param   pcCylinders     Where to store the number of cylinders. NULL is ok.
    1486  * @param   pcHeads         Where to store the number of heads. NULL is ok.
    1487  * @param   pcSectors       Where to store the number of sectors. NULL is ok.
    1488  */
    1489 VBOXDDU_DECL(int) VDGetGeometry(PVBOXHDD pDisk, unsigned *pcCylinders,
    1490                                 unsigned *pcHeads, unsigned *pcSectors)
    1491 {
    1492     /* sanity check */
    1493     Assert(pDisk);
    1494     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1495 
     1902 * @param   pDisk           Pointer to HDD container.
     1903 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     1904 * @param   pPCHSGeometry   Where to store PCHS geometry. Not NULL.
     1905 */
     1906VBOXDDU_DECL(int) VDGetPCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     1907                                    PPDMMEDIAGEOMETRY pPCHSGeometry)
     1908{
    14961909    int rc = VINF_SUCCESS;
    1497     PVDIMAGE pImage = pDisk->pBase;
    1498     if (RT_UNLIKELY(!pImage))
    1499     {
    1500         Assert(pImage);
    1501         rc = VERR_VDI_NOT_OPENED;
    1502     }
    1503     else
    1504     {
    1505         if (pDisk->cCylinders != 0)
    1506         {
    1507             if (pcCylinders)
    1508                 *pcCylinders = pDisk->cCylinders;
    1509             if (pcHeads)
    1510                 *pcHeads = pDisk->cHeads;
    1511             if (pcSectors)
    1512                 *pcSectors = pDisk->cSectors;
     1910
     1911    LogFlowFunc(("pDisk=%#p nImage=%u pPCHSGeometry=%#p\n",
     1912                 pDisk, nImage, pPCHSGeometry));
     1913    do
     1914    {
     1915        /* sanity check */
     1916        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     1917        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1918
     1919        /* Check arguments. */
     1920        AssertMsgBreak(VALID_PTR(pPCHSGeometry),
     1921                       ("pPCHSGeometry=%#p\n", pPCHSGeometry),
     1922                       rc = VERR_INVALID_PARAMETER);
     1923
     1924        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     1925        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     1926
     1927        if (pImage == pDisk->pLast)
     1928        {
     1929            /* Use cached information if possible. */
     1930            if (pDisk->PCHSGeometry.cCylinders != 0)
     1931                *pPCHSGeometry = pDisk->PCHSGeometry;
     1932            else
     1933                rc = VERR_VDI_GEOMETRY_NOT_SET;
    15131934        }
    15141935        else
    1515             rc = VERR_VDI_GEOMETRY_NOT_SET;
    1516     }
    1517     LogFlow(("%s: %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc,
    1518              pDisk->cCylinders, pDisk->cHeads, pDisk->cSectors));
    1519     return rc;
    1520 }
    1521 
    1522 /**
    1523  * Store virtual disk geometry in HDD container.
     1936            rc = pDisk->Backend->pfnGetPCHSGeometry(pImage->pvBackendData,
     1937                                                    pPCHSGeometry);
     1938    } while (0);
     1939
     1940    LogFlowFunc(("%s: %Vrc (PCHS=%u/%u/%u)\n", rc,
     1941                 pDisk->PCHSGeometry.cCylinders, pDisk->PCHSGeometry.cHeads,
     1942                 pDisk->PCHSGeometry.cSectors));
     1943    return rc;
     1944}
     1945
     1946/**
     1947 * Store virtual disk PCHS geometry in HDD container.
    15241948 *
    15251949 * Note that in case of unrecoverable error all images in HDD container will be closed.
    15261950 *
    15271951 * @returns VBox status code.
    1528  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    1529  * @param   pDisk           Pointer to VBox HDD container.
    1530  * @param   cCylinders      Number of cylinders.
    1531  * @param   cHeads          Number of heads.
    1532  * @param   cSectors        Number of sectors.
    1533  */
    1534 VBOXDDU_DECL(int) VDSetGeometry(PVBOXHDD pDisk, unsigned cCylinders,
    1535                                 unsigned cHeads, unsigned cSectors)
    1536 {
    1537     /* sanity check */
    1538     Assert(pDisk);
    1539     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1540 
     1952 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     1953 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
     1954 * @param   pDisk           Pointer to HDD container.
     1955 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     1956 * @param   pPCHSGeometry   Where to load PCHS geometry from. Not NULL.
     1957 */
     1958VBOXDDU_DECL(int) VDSetPCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     1959                                    PCPDMMEDIAGEOMETRY pPCHSGeometry)
     1960{
    15411961    int rc = VINF_SUCCESS;
    1542     PVDIMAGE pImage = pDisk->pBase;
    1543     if (RT_UNLIKELY(!pImage))
    1544     {
    1545         Assert(pImage);
    1546         rc = VERR_VDI_NOT_OPENED;
    1547     }
    1548     else
    1549     {
    1550         if (    cCylinders != pDisk->cCylinders
    1551             ||  cHeads != pDisk->cHeads
    1552             ||  cSectors != pDisk->cSectors)
    1553         {
    1554             /* Only update geometry if it is changed. Avoids similar checks
    1555              * in every backend. Most of the time the new geometry is set to
    1556              * the previous values, so no need to go through the hassle of
    1557              * updating an image which could be opened in read-only mode right
    1558              * now. */
    1559             rc = pDisk->Backend->pfnSetGeometry(pImage->pvBackendData,
    1560                                                 cCylinders, cHeads, cSectors);
    1561 
    1562             /* Cache new geometry values in any case, whether successful or not. */
    1563             int rc2 = pDisk->Backend->pfnGetGeometry(pImage->pvBackendData,
    1564                                                      &pDisk->cCylinders,
    1565                                                      &pDisk->cHeads,
    1566                                                      &pDisk->cSectors);
    1567             if (VBOX_FAILURE(rc2))
     1962
     1963    LogFlowFunc(("pDisk=%#p nImage=%u pPCHSGeometry=%#p PCHS=%u/%u/%u\n",
     1964                 pDisk, nImage, pPCHSGeometry, pPCHSGeometry->cCylinders,
     1965                 pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
     1966    do
     1967    {
     1968        /* sanity check */
     1969        AssertBreak(VALID_PTR(pDisk), VERR_INVALID_PARAMETER);
     1970        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     1971
     1972        /* Check arguments. */
     1973        AssertMsgBreak(   VALID_PTR(pPCHSGeometry)
     1974                       && pPCHSGeometry->cCylinders <= 16383
     1975                       && pPCHSGeometry->cCylinders != 0
     1976                       && pPCHSGeometry->cHeads <= 16
     1977                       && pPCHSGeometry->cHeads != 0
     1978                       && pPCHSGeometry->cSectors <= 63
     1979                       && pPCHSGeometry->cSectors != 0,
     1980                       ("pPCHSGeometry=%#p PCHS=%u/%u/%u\n", pPCHSGeometry,
     1981                        pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads,
     1982                        pPCHSGeometry->cSectors),
     1983                       rc = VERR_INVALID_PARAMETER);
     1984
     1985        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     1986        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     1987
     1988        if (pImage == pDisk->pLast)
     1989        {
     1990            if (    pPCHSGeometry->cCylinders != pDisk->PCHSGeometry.cCylinders
     1991                ||  pPCHSGeometry->cHeads != pDisk->PCHSGeometry.cHeads
     1992                ||  pPCHSGeometry->cSectors != pDisk->PCHSGeometry.cSectors)
    15681993            {
    1569                 pDisk->cCylinders = 0;
    1570                 pDisk->cHeads = 0;
    1571                 pDisk->cSectors = 0;
     1994                /* Only update geometry if it is changed. Avoids similar checks
     1995                 * in every backend. Most of the time the new geometry is set
     1996                 * to the previous values, so no need to go through the hassle
     1997                 * of updating an image which could be opened in read-only mode
     1998                 * right now. */
     1999                rc = pDisk->Backend->pfnSetPCHSGeometry(pImage->pvBackendData,
     2000                                                        pPCHSGeometry);
     2001
     2002                /* Cache new geometry values in any case. */
     2003                int rc2 = pDisk->Backend->pfnGetPCHSGeometry(pImage->pvBackendData,
     2004                                                             &pDisk->PCHSGeometry);
     2005                if (VBOX_FAILURE(rc2))
     2006                {
     2007                    pDisk->PCHSGeometry.cCylinders = 0;
     2008                    pDisk->PCHSGeometry.cHeads = 0;
     2009                    pDisk->PCHSGeometry.cSectors = 0;
     2010                }
     2011                else
     2012                {
     2013                    /* Make sure the CHS geometry is properly clipped. */
     2014                    pDisk->PCHSGeometry.cCylinders = RT_MIN(pDisk->PCHSGeometry.cCylinders, 1024);
     2015                    pDisk->PCHSGeometry.cHeads = RT_MIN(pDisk->PCHSGeometry.cHeads, 255);
     2016                    pDisk->PCHSGeometry.cSectors = RT_MIN(pDisk->PCHSGeometry.cSectors, 63);
     2017                }
    15722018            }
     2019        }
     2020        else
     2021        {
     2022            PDMMEDIAGEOMETRY PCHS;
     2023            rc = pDisk->Backend->pfnGetPCHSGeometry(pImage->pvBackendData,
     2024                                                    &PCHS);
     2025            if (    VBOX_FAILURE(rc)
     2026                ||  pPCHSGeometry->cCylinders != PCHS.cCylinders
     2027                ||  pPCHSGeometry->cHeads != PCHS.cHeads
     2028                ||  pPCHSGeometry->cSectors != PCHS.cSectors)
     2029            {
     2030                /* Only update geometry if it is changed. Avoids similar checks
     2031                 * in every backend. Most of the time the new geometry is set
     2032                 * to the previous values, so no need to go through the hassle
     2033                 * of updating an image which could be opened in read-only mode
     2034                 * right now. */
     2035                rc = pDisk->Backend->pfnSetPCHSGeometry(pImage->pvBackendData,
     2036                                                        pPCHSGeometry);
     2037            }
     2038        }
     2039    } while (0);
     2040
     2041    LogFlowFunc(("returns %Vrc\n", rc));
     2042    return rc;
     2043}
     2044
     2045/**
     2046 * Get virtual disk LCHS geometry stored in HDD container.
     2047 *
     2048 * @returns VBox status code.
     2049 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     2050 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
     2051 * @param   pDisk           Pointer to HDD container.
     2052 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     2053 * @param   pLCHSGeometry   Where to store LCHS geometry. Not NULL.
     2054 */
     2055VBOXDDU_DECL(int) VDGetLCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     2056                                    PPDMMEDIAGEOMETRY pLCHSGeometry)
     2057{
     2058    int rc = VINF_SUCCESS;
     2059
     2060    LogFlowFunc(("pDisk=%#p nImage=%u pLCHSGeometry=%#p\n",
     2061                 pDisk, nImage, pLCHSGeometry));
     2062    do
     2063    {
     2064        /* sanity check */
     2065        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2066        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2067
     2068        /* Check arguments. */
     2069        AssertMsgBreak(VALID_PTR(pLCHSGeometry),
     2070                       ("pLCHSGeometry=%#p\n", pLCHSGeometry),
     2071                       rc = VERR_INVALID_PARAMETER);
     2072
     2073        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2074        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2075
     2076        if (pImage == pDisk->pLast)
     2077        {
     2078            /* Use cached information if possible. */
     2079            if (pDisk->LCHSGeometry.cCylinders != 0)
     2080                *pLCHSGeometry = pDisk->LCHSGeometry;
    15732081            else
     2082                rc = VERR_VDI_GEOMETRY_NOT_SET;
     2083        }
     2084        else
     2085            rc = pDisk->Backend->pfnGetLCHSGeometry(pImage->pvBackendData,
     2086                                                    pLCHSGeometry);
     2087    } while (0);
     2088
     2089    LogFlowFunc(("%s: %Vrc (LCHS=%u/%u/%u)\n", rc,
     2090                 pDisk->LCHSGeometry.cCylinders, pDisk->LCHSGeometry.cHeads,
     2091                 pDisk->LCHSGeometry.cSectors));
     2092    return rc;
     2093}
     2094
     2095/**
     2096 * Store virtual disk LCHS geometry in HDD container.
     2097 *
     2098 * Note that in case of unrecoverable error all images in HDD container will be closed.
     2099 *
     2100 * @returns VBox status code.
     2101 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     2102 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
     2103 * @param   pDisk           Pointer to HDD container.
     2104 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     2105 * @param   pLCHSGeometry   Where to load LCHS geometry from. Not NULL.
     2106 */
     2107VBOXDDU_DECL(int) VDSetLCHSGeometry(PVBOXHDD pDisk, unsigned nImage,
     2108                                    PCPDMMEDIAGEOMETRY pLCHSGeometry)
     2109{
     2110    int rc = VINF_SUCCESS;
     2111
     2112    LogFlowFunc(("pDisk=%#p nImage=%u pLCHSGeometry=%#p LCHS=%u/%u/%u\n",
     2113                 pDisk, nImage, pLCHSGeometry, pLCHSGeometry->cCylinders,
     2114                 pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
     2115    do
     2116    {
     2117        /* sanity check */
     2118        AssertBreak(VALID_PTR(pDisk), VERR_INVALID_PARAMETER);
     2119        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2120
     2121        /* Check arguments. */
     2122        AssertMsgBreak(   VALID_PTR(pLCHSGeometry)
     2123                       && pLCHSGeometry->cCylinders <= 1024
     2124                       && pLCHSGeometry->cCylinders != 0
     2125                       && pLCHSGeometry->cHeads <= 255
     2126                       && pLCHSGeometry->cHeads != 0
     2127                       && pLCHSGeometry->cSectors <= 63
     2128                       && pLCHSGeometry->cSectors != 0,
     2129                       ("pLCHSGeometry=%#p LCHS=%u/%u/%u\n", pLCHSGeometry,
     2130                        pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads,
     2131                        pLCHSGeometry->cSectors),
     2132                       rc = VERR_INVALID_PARAMETER);
     2133
     2134        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2135        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2136
     2137        if (pImage == pDisk->pLast)
     2138        {
     2139            if (    pLCHSGeometry->cCylinders != pDisk->LCHSGeometry.cCylinders
     2140                ||  pLCHSGeometry->cHeads != pDisk->LCHSGeometry.cHeads
     2141                ||  pLCHSGeometry->cSectors != pDisk->LCHSGeometry.cSectors)
    15742142            {
    1575                 /* Make sure the CHS geometry is properly clipped. */
    1576                 pDisk->cCylinders = RT_MIN(pDisk->cCylinders, 16383);
    1577                 pDisk->cHeads = RT_MIN(pDisk->cHeads, 255);
    1578                 pDisk->cSectors = RT_MIN(pDisk->cSectors, 255);
     2143                /* Only update geometry if it is changed. Avoids similar checks
     2144                 * in every backend. Most of the time the new geometry is set
     2145                 * to the previous values, so no need to go through the hassle
     2146                 * of updating an image which could be opened in read-only mode
     2147                 * right now. */
     2148                rc = pDisk->Backend->pfnSetLCHSGeometry(pImage->pvBackendData,
     2149                                                        pLCHSGeometry);
     2150
     2151                /* Cache new geometry values in any case. */
     2152                int rc2 = pDisk->Backend->pfnGetLCHSGeometry(pImage->pvBackendData,
     2153                                                             &pDisk->LCHSGeometry);
     2154                if (VBOX_FAILURE(rc2))
     2155                {
     2156                    pDisk->LCHSGeometry.cCylinders = 0;
     2157                    pDisk->LCHSGeometry.cHeads = 0;
     2158                    pDisk->LCHSGeometry.cSectors = 0;
     2159                }
     2160                else
     2161                {
     2162                    /* Make sure the CHS geometry is properly clipped. */
     2163                    pDisk->LCHSGeometry.cCylinders = RT_MIN(pDisk->LCHSGeometry.cCylinders, 1024);
     2164                    pDisk->LCHSGeometry.cHeads = RT_MIN(pDisk->LCHSGeometry.cHeads, 255);
     2165                    pDisk->LCHSGeometry.cSectors = RT_MIN(pDisk->LCHSGeometry.cSectors, 63);
     2166                }
    15792167            }
    15802168        }
    1581     }
    1582 
    1583     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    1584     return rc;
    1585 }
    1586 
    1587 /**
    1588  * Get virtual disk translation mode stored in HDD container.
    1589  *
    1590  * @returns VBox status code.
    1591  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    1592  * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the HDD container.
    1593  * @param   pDisk           Pointer to VBox HDD container.
    1594  * @param   penmTranslation Where to store the translation mode (see pdm.h).
    1595  */
    1596 VBOXDDU_DECL(int) VDGetTranslation(PVBOXHDD pDisk,
    1597                                    PPDMBIOSTRANSLATION penmTranslation)
    1598 {
    1599     /* sanity check */
    1600     Assert(pDisk);
    1601     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1602 
    1603     int rc = VINF_SUCCESS;
    1604     PVDIMAGE pImage = pDisk->pBase;
    1605     if (RT_UNLIKELY(!pImage))
    1606     {
    1607         Assert(pImage);
    1608         rc = VERR_VDI_NOT_OPENED;
    1609     }
    1610     else
    1611     {
    1612         if (pDisk->enmTranslation != 0)
    1613             *penmTranslation = pDisk->enmTranslation;
    16142169        else
    1615             rc = VERR_VDI_GEOMETRY_NOT_SET;
    1616     }
    1617     LogFlow(("%s: %Vrc (translation=%u)\n", __FUNCTION__, rc,
    1618              pDisk->enmTranslation));
    1619     return rc;
    1620 }
    1621 
    1622 /**
    1623  * Store virtual disk translation mode in HDD container.
    1624  *
    1625  * Note that in case of unrecoverable error all images in HDD container will be closed.
    1626  *
    1627  * @returns VBox status code.
    1628  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    1629  * @param   pDisk           Pointer to VBox HDD container.
    1630  * @param   enmTranslation  Translation mode (see pdm.h).
    1631  */
    1632 VBOXDDU_DECL(int) VDSetTranslation(PVBOXHDD pDisk,
    1633                                    PDMBIOSTRANSLATION enmTranslation)
    1634 {
    1635     /* sanity check */
    1636     Assert(pDisk);
    1637     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1638 
    1639     int rc = VINF_SUCCESS;
    1640     PVDIMAGE pImage = pDisk->pBase;
    1641     if (RT_UNLIKELY(!pImage))
    1642     {
    1643         Assert(pImage);
    1644         rc = VERR_VDI_NOT_OPENED;
    1645     }
    1646     else
    1647     {
    1648         if (enmTranslation == 0)
    1649             rc = VERR_INVALID_PARAMETER;
    1650         else if (enmTranslation != pDisk->enmTranslation)
    1651         {
    1652             /* Only update translation mode if it is changed. Avoids similar
    1653              * checks in every backend. Most of the time the new translation
    1654              * mode is set to the previous value, so no need to go through the
    1655              * hassle of updating an image which could be opened in read-only
    1656              * mode right now. */
    1657             rc = pDisk->Backend->pfnSetTranslation(pImage->pvBackendData,
    1658                                                    enmTranslation);
    1659 
    1660             /* Cache new translation mode in any case, whether successful or not. */
    1661             int rc2 = pDisk->Backend->pfnGetTranslation(pImage->pvBackendData,
    1662                                                         &pDisk->enmTranslation);
    1663             if (VBOX_FAILURE(rc2))
    1664                 pDisk->enmTranslation = (PDMBIOSTRANSLATION)0;
    1665         }
    1666     }
    1667 
    1668     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     2170        {
     2171            PDMMEDIAGEOMETRY LCHS;
     2172            rc = pDisk->Backend->pfnGetLCHSGeometry(pImage->pvBackendData,
     2173                                                    &LCHS);
     2174            if (    VBOX_FAILURE(rc)
     2175                ||  pLCHSGeometry->cCylinders != LCHS.cCylinders
     2176                ||  pLCHSGeometry->cHeads != LCHS.cHeads
     2177                ||  pLCHSGeometry->cSectors != LCHS.cSectors)
     2178            {
     2179                /* Only update geometry if it is changed. Avoids similar checks
     2180                 * in every backend. Most of the time the new geometry is set
     2181                 * to the previous values, so no need to go through the hassle
     2182                 * of updating an image which could be opened in read-only mode
     2183                 * right now. */
     2184                rc = pDisk->Backend->pfnSetLCHSGeometry(pImage->pvBackendData,
     2185                                                        pLCHSGeometry);
     2186            }
     2187        }
     2188    } while (0);
     2189
     2190    LogFlowFunc(("returns %Vrc\n", rc));
    16692191    return rc;
    16702192}
     
    16752197 * @returns VBox status code.
    16762198 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1677  * @param   pDisk           Pointer to VBox HDD container.
     2199 * @param   pDisk           Pointer to HDD container.
    16782200 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    16792201 * @param   puVersion       Where to store the image version.
     
    16822204                               unsigned *puVersion)
    16832205{
    1684     return VERR_NOT_IMPLEMENTED;
     2206    int rc = VINF_SUCCESS;
     2207
     2208    LogFlowFunc(("pDisk=%#p nImage=%u puVersion=%#p\n",
     2209                 pDisk, nImage, puVersion));
     2210    do
     2211    {
     2212        /* sanity check */
     2213        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2214        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2215
     2216        /* Check arguments. */
     2217        AssertMsgBreak(VALID_PTR(puVersion),
     2218                       ("puVersion=%#p\n", puVersion),
     2219                       rc = VERR_INVALID_PARAMETER);
     2220
     2221        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2222        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2223
     2224        *puVersion = pDisk->Backend->pfnGetVersion(pImage->pvBackendData);
     2225    } while (0);
     2226
     2227    LogFlowFunc(("returns %Vrc uVersion=%#x\n", rc, *puVersion));
     2228    return rc;
    16852229}
    16862230
     
    16902234 * @returns VBox status code.
    16912235 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1692  * @param   pDisk           Pointer to VBox HDD container.
     2236 * @param   pDisk           Pointer to HDD container.
    16932237 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    16942238 * @param   penmType        Where to store the image type.
     
    16972241                                 PVDIMAGETYPE penmType)
    16982242{
    1699     return VERR_NOT_IMPLEMENTED;
     2243    int rc;
     2244
     2245    LogFlowFunc(("pDisk=%#p nImage=%u penmType=%#p\n",
     2246                 pDisk, nImage, penmType));
     2247    do
     2248    {
     2249        /* sanity check */
     2250        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2251        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2252
     2253        /* Check arguments. */
     2254        AssertMsgBreak(VALID_PTR(penmType),
     2255                       ("penmType=%#p\n", penmType),
     2256                       rc = VERR_INVALID_PARAMETER);
     2257
     2258        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2259        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2260
     2261        rc = pDisk->Backend->pfnGetImageType(pImage->pvBackendData,
     2262                                             penmType);
     2263    } while (0);
     2264
     2265    LogFlowFunc(("returns %Vrc uenmType=%u\n", rc, *penmType));
     2266    return rc;
    17002267}
    17012268
     
    17052272 * @returns VBox status code.
    17062273 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1707  * @param   pDisk           Pointer to VBox HDD container.
     2274 * @param   pDisk           Pointer to HDD container.
    17082275 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    17092276 * @param   puImageFlags    Where to store the image flags.
     
    17122279                                  unsigned *puImageFlags)
    17132280{
    1714     return VERR_NOT_IMPLEMENTED;
    1715 }
    1716 
    1717 /**
    1718  * Get open flags of last opened image in HDD container.
    1719  *
    1720  * @returns VBox status code.
    1721  * @returns VERR_VDI_NOT_OPENED if no image is opened in HDD container.
    1722  * @param   pDisk           Pointer to VBox HDD container.
     2281    int rc = VINF_SUCCESS;
     2282
     2283    LogFlowFunc(("pDisk=%#p nImage=%u puImageFlags=%#p\n",
     2284                 pDisk, nImage, puImageFlags));
     2285    do
     2286    {
     2287        /* sanity check */
     2288        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2289        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2290
     2291        /* Check arguments. */
     2292        AssertMsgBreak(VALID_PTR(puImageFlags),
     2293                       ("puImageFlags=%#p\n", puImageFlags),
     2294                       rc = VERR_INVALID_PARAMETER);
     2295
     2296        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2297        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2298
     2299        *puImageFlags = pDisk->Backend->pfnGetImageFlags(pImage->pvBackendData);
     2300    } while (0);
     2301
     2302    LogFlowFunc(("returns %Vrc uImageFlags=%#x\n", rc, *puImageFlags));
     2303    return rc;
     2304}
     2305
     2306/**
     2307 * Get open flags of image in HDD container.
     2308 *
     2309 * @returns VBox status code.
     2310 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     2311 * @param   pDisk           Pointer to HDD container.
     2312 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    17232313 * @param   puOpenFlags     Where to store the image open flags.
    17242314 */
    1725 VBOXDDU_DECL(int) VDGetOpenFlags(PVBOXHDD pDisk, unsigned *puOpenFlags)
    1726 {
    1727     /* sanity check */
    1728     Assert(pDisk);
    1729     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1730 
    1731     unsigned uOpenFlags = 0;
     2315VBOXDDU_DECL(int) VDGetOpenFlags(PVBOXHDD pDisk, unsigned nImage,
     2316                                 unsigned *puOpenFlags)
     2317{
    17322318    int rc = VINF_SUCCESS;
    1733     PVDIMAGE pImage = pDisk->pLast;
    1734     if (RT_UNLIKELY(!pImage))
    1735     {
    1736         Assert(pImage);
    1737         rc = VERR_VDI_NOT_OPENED;
    1738     }
    1739     else
    1740     {
    1741         uOpenFlags = pDisk->Backend->pfnGetOpenFlags(pDisk->pLast->pvBackendData);
    1742         *puOpenFlags = uOpenFlags;
    1743     }
    1744     LogFlow(("%s: returns %Vrc uOpenFlags=%#x\n", __FUNCTION__, rc, uOpenFlags));
    1745     return uOpenFlags;
    1746 }
    1747 
    1748 /**
    1749  * Set open flags of last opened image in HDD container.
     2319
     2320    LogFlowFunc(("pDisk=%#p nImage=%u puOpenFlags=%#p\n",
     2321                 pDisk, nImage, puOpenFlags));
     2322    do
     2323    {
     2324        /* sanity check */
     2325        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2326        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2327
     2328        /* Check arguments. */
     2329        AssertMsgBreak(VALID_PTR(puOpenFlags),
     2330                       ("puOpenFlags=%#p\n", puOpenFlags),
     2331                       rc = VERR_INVALID_PARAMETER);
     2332
     2333        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2334        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2335
     2336        *puOpenFlags = pDisk->Backend->pfnGetOpenFlags(pImage->pvBackendData);
     2337    } while (0);
     2338
     2339    LogFlowFunc(("returns %Vrc uOpenFlags=%#x\n", rc, *puOpenFlags));
     2340    return rc;
     2341}
     2342
     2343/**
     2344 * Set open flags of image in HDD container.
    17502345 * This operation may cause file locking changes and/or files being reopened.
    17512346 * Note that in case of unrecoverable error all images in HDD container will be closed.
    17522347 *
    1753  * @returns Virtual disk block size in bytes.
     2348 * @returns VBox status code.
    17542349 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1755  * @returns VBox status code.
    1756  * @param   pDisk           Pointer to VBox HDD container.
     2350 * @param   pDisk           Pointer to HDD container.
     2351 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    17572352 * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
    17582353 */
    1759 VBOXDDU_DECL(int) VDSetOpenFlags(PVBOXHDD pDisk, unsigned uOpenFlags)
    1760 {
    1761     /* sanity check */
    1762     Assert(pDisk);
    1763     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1764 
    1765     int rc = VINF_SUCCESS;
    1766     PVDIMAGE pImage = pDisk->pLast;
    1767     if (RT_UNLIKELY(!pImage))
    1768     {
    1769         Assert(pImage);
    1770         rc = VERR_VDI_NOT_OPENED;
    1771     }
    1772     else
    1773         rc = pDisk->Backend->pfnSetOpenFlags(pDisk->pLast->pvBackendData,
     2354VBOXDDU_DECL(int) VDSetOpenFlags(PVBOXHDD pDisk, unsigned nImage,
     2355                                 unsigned uOpenFlags)
     2356{
     2357    int rc;
     2358
     2359    LogFlowFunc(("pDisk=%#p uOpenFlags=%#u\n", pDisk, uOpenFlags));
     2360    do
     2361    {
     2362        /* sanity check */
     2363        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2364        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2365
     2366        /* Check arguments. */
     2367        AssertMsgBreak((uOpenFlags & ~VD_OPEN_FLAGS_MASK) == 0,
     2368                       ("uOpenFlags=%#x\n", uOpenFlags),
     2369                       rc = VERR_INVALID_PARAMETER);
     2370
     2371        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2372        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2373
     2374        rc = pDisk->Backend->pfnSetOpenFlags(pImage->pvBackendData,
    17742375                                             uOpenFlags);
    1775     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     2376    } while (0);
     2377
     2378    LogFlowFunc(("returns %Vrc\n", rc));
    17762379    return rc;
    17772380}
     
    17792382/**
    17802383 * Get base filename of image in HDD container. Some image formats use
    1781  * other filenames as well, so don't use this for anything but for informational
     2384 * other filenames as well, so don't use this for anything but informational
    17822385 * purposes.
    17832386 *
     
    17852388 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    17862389 * @returns VERR_BUFFER_OVERFLOW if pszFilename buffer too small to hold filename.
    1787  * @param   pDisk           Pointer to VBox HDD container.
     2390 * @param   pDisk           Pointer to HDD container.
    17882391 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    17892392 * @param   pszFilename     Where to store the image file name.
     
    17932396                                char *pszFilename, unsigned cbFilename)
    17942397{
    1795     return VERR_NOT_IMPLEMENTED;
     2398    int rc;
     2399
     2400    LogFlowFunc(("pDisk=%#p nImage=%u pszFilename=%#p cbFilename=%u\n",
     2401                 pDisk, nImage, pszFilename, cbFilename));
     2402    do
     2403    {
     2404        /* sanity check */
     2405        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2406        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2407
     2408        /* Check arguments. */
     2409        AssertMsgBreak(VALID_PTR(pszFilename) && *pszFilename,
     2410                       ("pszFilename=%#p \"%s\"\n", pszFilename, pszFilename),
     2411                       rc = VERR_INVALID_PARAMETER);
     2412        AssertMsgBreak(cbFilename,
     2413                       ("cbFilename=%u\n", cbFilename),
     2414                       rc = VERR_INVALID_PARAMETER);
     2415
     2416        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2417        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2418
     2419        size_t cb = strlen(pImage->pszFilename);
     2420        if (cb <= cbFilename)
     2421        {
     2422            strcpy(pszFilename, pImage->pszFilename);
     2423            rc = VINF_SUCCESS;
     2424        }
     2425        else
     2426        {
     2427            strncpy(pszFilename, pImage->pszFilename, cbFilename - 1);
     2428            pszFilename[cbFilename - 1] = '\0';
     2429            rc = VERR_BUFFER_OVERFLOW;
     2430        }
     2431    } while (0);
     2432
     2433    LogFlowFunc(("returns %Vrc, pszFilename=\"%s\"\n", rc, pszFilename));
     2434    return rc;
    17962435}
    17972436
     
    18022441 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    18032442 * @returns VERR_BUFFER_OVERFLOW if pszComment buffer too small to hold comment text.
    1804  * @param   pDisk           Pointer to VBox HDD container.
     2443 * @param   pDisk           Pointer to HDD container.
    18052444 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    18062445 * @param   pszComment      Where to store the comment string of image. NULL is ok.
     
    18102449                               char *pszComment, unsigned cbComment)
    18112450{
    1812     /* sanity check */
    1813     Assert(pDisk);
    1814     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1815     Assert(pszComment);
    1816 
    1817     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
    18182451    int rc;
    1819     if (pImage)
     2452
     2453    LogFlowFunc(("pDisk=%#p nImage=%u pszComment=%#p cbComment=%u\n",
     2454                 pDisk, nImage, pszComment, cbComment));
     2455    do
     2456    {
     2457        /* sanity check */
     2458        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2459        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2460
     2461        /* Check arguments. */
     2462        AssertMsgBreak(VALID_PTR(pszComment),
     2463                       ("pszComment=%#p \"%s\"\n", pszComment, pszComment),
     2464                       rc = VERR_INVALID_PARAMETER);
     2465        AssertMsgBreak(cbComment,
     2466                       ("cbComment=%u\n", cbComment),
     2467                       rc = VERR_INVALID_PARAMETER);
     2468
     2469        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2470        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2471
    18202472        rc = pDisk->Backend->pfnGetComment(pImage->pvBackendData, pszComment,
    18212473                                           cbComment);
    1822     else
    1823         rc = VERR_VDI_IMAGE_NOT_FOUND;
    1824 
    1825     LogFlow(("%s: returns %Vrc, comment='%s' nImage=%u\n", __FUNCTION__,
    1826              rc, pszComment, nImage));
     2474    } while (0);
     2475
     2476    LogFlowFunc(("returns %Vrc, pszComment=\"%s\"\n", rc, pszComment));
    18272477    return rc;
    18282478}
     
    18332483 * @returns VBox status code.
    18342484 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1835  * @param   pDisk           Pointer to VBox HDD container.
     2485 * @param   pDisk           Pointer to HDD container.
    18362486 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    18372487 * @param   pszComment      New comment string (UTF-8). NULL is allowed to reset the comment.
     
    18402490                               const char *pszComment)
    18412491{
    1842     /* sanity check */
    1843     Assert(pDisk);
    1844     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1845     LogFlow(("%s: comment='%s' nImage=%u\n", __FUNCTION__, pszComment, nImage));
    1846 
    1847     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
    18482492    int rc;
    1849     if (pImage)
     2493
     2494    LogFlowFunc(("pDisk=%#p nImage=%u pszComment=%#p \"%s\"\n",
     2495                 pDisk, nImage, pszComment, pszComment));
     2496    do
     2497    {
     2498        /* sanity check */
     2499        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2500        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2501
     2502        /* Check arguments. */
     2503        AssertMsgBreak(VALID_PTR(pszComment) || pszComment == NULL,
     2504                       ("pszComment=%#p \"%s\"\n", pszComment, pszComment),
     2505                       rc = VERR_INVALID_PARAMETER);
     2506
     2507        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2508        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2509
    18502510        rc = pDisk->Backend->pfnSetComment(pImage->pvBackendData, pszComment);
    1851     else
    1852         rc = VERR_VDI_IMAGE_NOT_FOUND;
    1853 
    1854     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     2511    } while (0);
     2512
     2513    LogFlowFunc(("returns %Vrc\n", rc));
    18552514    return rc;
    18562515}
     
    18622521 * @returns VBox status code.
    18632522 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1864  * @param   pDisk           Pointer to VBox HDD container.
     2523 * @param   pDisk           Pointer to HDD container.
    18652524 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    18662525 * @param   pUuid           Where to store the image creation UUID.
     
    18682527VBOXDDU_DECL(int) VDGetUuid(PVBOXHDD pDisk, unsigned nImage, PRTUUID pUuid)
    18692528{
    1870     /* sanity check */
    1871     Assert(pDisk);
    1872     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1873     Assert(pUuid);
    1874 
    1875     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
    18762529    int rc;
    1877     if (pImage)
     2530
     2531    LogFlowFunc(("pDisk=%#p nImage=%u pUuid=%#p\n", pDisk, nImage, pUuid));
     2532    do
     2533    {
     2534        /* sanity check */
     2535        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2536        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2537
     2538        /* Check arguments. */
     2539        AssertMsgBreak(VALID_PTR(pUuid),
     2540                       ("pUuid=%#p\n", pUuid),
     2541                       rc = VERR_INVALID_PARAMETER);
     2542
     2543        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2544        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2545
    18782546        rc = pDisk->Backend->pfnGetUuid(pImage->pvBackendData, pUuid);
    1879     else
    1880         rc = VERR_VDI_IMAGE_NOT_FOUND;
    1881 
    1882     LogFlow(("%s: returns %Vrc, uuid={%Vuuid} nImage=%u\n", __FUNCTION__,
    1883              rc, pUuid, nImage));
     2547    } while (0);
     2548
     2549    LogFlowFunc(("returns %Vrc, Uuid={%Vuuid}\n", rc, pUuid));
    18842550    return rc;
    18852551}
     
    18902556 * @returns VBox status code.
    18912557 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1892  * @param   pDisk           Pointer to VBox HDD container.
     2558 * @param   pDisk           Pointer to HDD container.
    18932559 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    1894  * @param   pUuid           Optional parameter, new UUID of the image.
     2560 * @param   pUuid           New UUID of the image. If NULL, a new UUID is created.
    18952561 */
    18962562VBOXDDU_DECL(int) VDSetUuid(PVBOXHDD pDisk, unsigned nImage, PCRTUUID pUuid)
    18972563{
    1898     LogFlow(("%s: uuid={%Vuuid} nImage=%u\n", __FUNCTION__, pUuid, nImage));
    1899     /* sanity check */
    1900     Assert(pDisk);
    1901     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1902     Assert(pUuid);
    1903 
    1904     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
    19052564    int rc;
    1906     if (pImage)
     2565
     2566    LogFlowFunc(("pDisk=%#p nImage=%u pUuid=%#p {%Vuuid}\n",
     2567                 pDisk, nImage, pUuid, pUuid));
     2568    do
     2569    {
     2570        /* sanity check */
     2571        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2572        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2573
     2574        AssertMsgBreak(VALID_PTR(pUuid) || pUuid == NULL,
     2575                       ("pUuid=%#p\n", pUuid),
     2576                       rc = VERR_INVALID_PARAMETER);
     2577
     2578        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2579        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2580
     2581        RTUUID Uuid;
     2582        if (!pUuid)
     2583        {
     2584            RTUuidCreate(&Uuid);
     2585            pUuid = &Uuid;
     2586        }
    19072587        rc = pDisk->Backend->pfnSetUuid(pImage->pvBackendData, pUuid);
    1908     else
    1909         rc = VERR_VDI_IMAGE_NOT_FOUND;
    1910 
    1911     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     2588    } while (0);
     2589
     2590    LogFlowFunc(("returns %Vrc\n", rc));
    19122591    return rc;
    19132592}
     
    19182597 * @returns VBox status code.
    19192598 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1920  * @param   pDisk           Pointer to VBox HDD container.
     2599 * @param   pDisk           Pointer to HDD container.
    19212600 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    19222601 * @param   pUuid           Where to store the image modification UUID.
     
    19242603VBOXDDU_DECL(int) VDGetModificationUuid(PVBOXHDD pDisk, unsigned nImage, PRTUUID pUuid)
    19252604{
    1926     /* sanity check */
    1927     Assert(pDisk);
    1928     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1929     Assert(pUuid);
    1930 
    1931     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2605    int rc = VINF_SUCCESS;
     2606
     2607    LogFlowFunc(("pDisk=%#p nImage=%u pUuid=%#p\n", pDisk, nImage, pUuid));
     2608    do
     2609    {
     2610        /* sanity check */
     2611        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2612        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2613
     2614        /* Check arguments. */
     2615        AssertMsgBreak(VALID_PTR(pUuid),
     2616                       ("pUuid=%#p\n", pUuid),
     2617                       rc = VERR_INVALID_PARAMETER);
     2618
     2619        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2620        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2621
     2622        rc = pDisk->Backend->pfnGetModificationUuid(pImage->pvBackendData,
     2623                                                    pUuid);
     2624    } while (0);
     2625
     2626    LogFlowFunc(("returns %Vrc, Uuid={%Vuuid}\n", rc, pUuid));
     2627    return rc;
     2628}
     2629
     2630/**
     2631 * Set the image's last modification UUID. Should not be used by normal applications.
     2632 *
     2633 * @returns VBox status code.
     2634 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
     2635 * @param   pDisk           Pointer to HDD container.
     2636 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     2637 * @param   pUuid           New modification UUID of the image. If NULL, a new UUID is created.
     2638 */
     2639VBOXDDU_DECL(int) VDSetModificationUuid(PVBOXHDD pDisk, unsigned nImage, PCRTUUID pUuid)
     2640{
    19322641    int rc;
    1933     if (pImage)
    1934         rc = pDisk->Backend->pfnGetModificationUuid(pImage->pvBackendData, pUuid);
    1935     else
    1936         rc = VERR_VDI_IMAGE_NOT_FOUND;
    1937 
    1938     LogFlow(("%s: returns %Vrc, uuid={%Vuuid} nImage=%u\n", __FUNCTION__,
    1939              rc, pUuid, nImage));
    1940     return rc;
    1941 }
    1942 
    1943 /**
    1944  * Set the image's last modification UUID. Should not be used by normal applications.
     2642
     2643    LogFlowFunc(("pDisk=%#p nImage=%u pUuid=%#p {%Vuuid}\n",
     2644                 pDisk, nImage, pUuid, pUuid));
     2645    do
     2646    {
     2647        /* sanity check */
     2648        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2649        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2650
     2651        /* Check arguments. */
     2652        AssertMsgBreak(VALID_PTR(pUuid) || pUuid == NULL,
     2653                       ("pUuid=%#p\n", pUuid),
     2654                       rc = VERR_INVALID_PARAMETER);
     2655
     2656        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2657        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2658
     2659        RTUUID Uuid;
     2660        if (!pUuid)
     2661        {
     2662            RTUuidCreate(&Uuid);
     2663            pUuid = &Uuid;
     2664        }
     2665        rc = pDisk->Backend->pfnSetModificationUuid(pImage->pvBackendData,
     2666                                                    pUuid);
     2667    } while (0);
     2668
     2669    LogFlowFunc(("returns %Vrc\n", rc));
     2670    return rc;
     2671}
     2672
     2673/**
     2674 * Get parent UUID of image in HDD container.
    19452675 *
    19462676 * @returns VBox status code.
    19472677 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1948  * @param   pDisk           Pointer to VBox HDD container.
    1949  * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    1950  * @param   pUuid           Optional parameter, new last modification UUID of the image.
    1951  */
    1952 VBOXDDU_DECL(int) VDSetModificationUuid(PVBOXHDD pDisk, unsigned nImage, PCRTUUID pUuid)
    1953 {
    1954     LogFlow(("%s: uuid={%Vuuid} nImage=%u\n", __FUNCTION__, pUuid, nImage));
    1955     /* sanity check */
    1956     Assert(pDisk);
    1957     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1958     Assert(pUuid);
    1959 
    1960     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
    1961     int rc;
    1962     if (pImage)
    1963         rc = pDisk->Backend->pfnSetModificationUuid(pImage->pvBackendData, pUuid);
    1964     else
    1965         rc = VERR_VDI_IMAGE_NOT_FOUND;
    1966 
    1967     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    1968     return rc;
    1969 }
    1970 
    1971 /**
    1972  * Get parent UUID of image in HDD container.
    1973  *
    1974  * @returns VBox status code.
    1975  * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
    1976  * @param   pDisk           Pointer to VBox HDD container.
     2678 * @param   pDisk           Pointer to HDD container.
    19772679 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    19782680 * @param   pUuid           Where to store the parent image UUID.
     
    19812683                                  PRTUUID pUuid)
    19822684{
    1983     /* sanity check */
    1984     Assert(pDisk);
    1985     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    1986     Assert(pUuid);
    1987 
    1988     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
    1989     int rc;
    1990     if (pImage)
     2685    int rc = VINF_SUCCESS;
     2686
     2687    LogFlowFunc(("pDisk=%#p nImage=%u pUuid=%#p\n", pDisk, nImage, pUuid));
     2688    do
     2689    {
     2690        /* sanity check */
     2691        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2692        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2693
     2694        /* Check arguments. */
     2695        AssertMsgBreak(VALID_PTR(pUuid),
     2696                       ("pUuid=%#p\n", pUuid),
     2697                       rc = VERR_INVALID_PARAMETER);
     2698
     2699        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2700        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2701
    19912702        rc = pDisk->Backend->pfnGetParentUuid(pImage->pvBackendData, pUuid);
    1992     else
    1993         rc = VERR_VDI_IMAGE_NOT_FOUND;
    1994 
    1995     LogFlow(("%s: returns %Vrc, uuid={%Vuuid} nImage=%u\n", __FUNCTION__,
    1996              rc, pUuid, nImage));
     2703    } while (0);
     2704
     2705    LogFlowFunc(("returns %Vrc, Uuid={%Vuuid}\n", rc, pUuid));
    19972706    return rc;
    19982707}
     
    20022711 *
    20032712 * @returns VBox status code.
    2004  * @param   pDisk           Pointer to VBox HDD container.
     2713 * @param   pDisk           Pointer to HDD container.
    20052714 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
    2006  * @param   pUuid           Optional parameter, new parent UUID of the image.
     2715 * @param   pUuid           New parent UUID of the image. If NULL, a new UUID is created.
    20072716 */
    20082717VBOXDDU_DECL(int) VDSetParentUuid(PVBOXHDD pDisk, unsigned nImage,
    20092718                                  PCRTUUID pUuid)
    20102719{
    2011     LogFlow(("%s: uuid={%Vuuid} nImage=%u\n", __FUNCTION__, pUuid, nImage));
    2012     /* sanity check */
    2013     Assert(pDisk);
    2014     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    2015     Assert(pUuid);
    2016 
    2017     PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
    20182720    int rc;
    2019     if (pImage)
     2721
     2722    LogFlowFunc(("pDisk=%#p nImage=%u pUuid=%#p {%Vuuid}\n",
     2723                 pDisk, nImage, pUuid, pUuid));
     2724    do
     2725    {
     2726        /* sanity check */
     2727        AssertBreak(VALID_PTR(pDisk), rc = VERR_INVALID_PARAMETER);
     2728        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2729
     2730        /* Check arguments. */
     2731        AssertMsgBreak(VALID_PTR(pUuid) || pUuid == NULL,
     2732                       ("pUuid=%#p\n", pUuid),
     2733                       rc = VERR_INVALID_PARAMETER);
     2734
     2735        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2736        AssertBreak(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
     2737
     2738        RTUUID Uuid;
     2739        if (!pUuid)
     2740        {
     2741            RTUuidCreate(&Uuid);
     2742            pUuid = &Uuid;
     2743        }
    20202744        rc = pDisk->Backend->pfnSetParentUuid(pImage->pvBackendData, pUuid);
    2021     else
    2022         rc = VERR_VDI_IMAGE_NOT_FOUND;
    2023 
    2024     LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
     2745    } while (0);
     2746
     2747    LogFlowFunc(("returns %Vrc\n", rc));
    20252748    return rc;
    20262749}
     
    20302753 * Debug helper - dumps all opened images in HDD container into the log file.
    20312754 *
    2032  * @param   pDisk           Pointer to VDI HDD container.
     2755 * @param   pDisk           Pointer to HDD container.
    20332756 */
    20342757VBOXDDU_DECL(void) VDDumpImages(PVBOXHDD pDisk)
    20352758{
    2036     /* sanity check */
    2037     Assert(pDisk);
    2038     AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    2039 
    2040     RTLogPrintf("--- Dumping VDI Disk, Images=%u\n", pDisk->cImages);
    2041     for (PVDIMAGE pImage = pDisk->pBase; pImage; pImage = pImage->pNext)
    2042     {
    2043         RTLogPrintf("Dumping VDI image \"%s\" file=%#p\n", pImage->pszFilename);
    2044         /** @todo call backend to print its part. */
    2045     }
    2046 }
    2047 
     2759    do
     2760    {
     2761        /* sanity check */
     2762        AssertBreak(VALID_PTR(pDisk), );
     2763        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     2764
     2765        RTLogPrintf("--- Dumping VD Disk, Backend=%s, Images=%u\n",
     2766                    pDisk->Backend->pszBackendName, pDisk->cImages);
     2767        for (PVDIMAGE pImage = pDisk->pBase; pImage; pImage = pImage->pNext)
     2768        {
     2769            RTLogPrintf("Dumping VD image \"%s\"\n", pImage->pszFilename);
     2770            pDisk->Backend->pfnDump(pImage->pvBackendData);
     2771        }
     2772    } while (0);
     2773}
     2774
  • trunk/src/VBox/Devices/Storage/VBoxHDD-newInternal.h

    • Property svn:eol-style set to native
    r6196 r6291  
    44
    55/*
    6  * Copyright (C) 2006-2007 innotek GmbH
     6 * Copyright (C) 2006-2008 innotek GmbH
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2727{
    2828    /**
     29     * The name of the backend (constant string).
     30     */
     31    const char *pszBackendName;
     32
     33    /**
    2934     * The size of the structure.
    3035     */
     
    3237
    3338    /**
    34      * Check if an file is valid for the backend.
    35      *
    36      * @returns VBox status code.
    37      * @param   pszFilename     Name of the image file to open. Guaranteed to be available and
    38      *                          unchanged during the lifetime of this image.
     39     * Check if a file is valid for the backend.
     40     *
     41     * @returns VBox status code.
     42     * @param   pszFilename     Name of the image file.
    3943     */
    4044    DECLR3CALLBACKMEMBER(int, pfnCheckIfValid, (const char *pszFilename));
     
    6367     * @param   uImageFlags     Flags specifying special image features.
    6468     * @param   pszComment      Pointer to image comment. NULL is ok.
    65      * @param   cCylinders      Number of cylinders (must be <= 16383).
    66      * @param   cHeads          Number of heads (must be <= 16).
    67      * @param   cSectors        Number of sectors (must be <= 63).
     69     * @param   pPCHSGeometry   Physical drive geometry CHS <= (16383,16,255).
     70     * @param   pLCHSGeometry   Logical drive geometry CHS <= (1024,255,63).
    6871     * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
    6972     * @param   pfnProgress     Progress callback. Optional. NULL if not to be used.
    7073     * @param   pvUser          User argument for the progress callback.
     74     * @param   uPercentStart   Starting value for progress percentage.
     75     * @param   uPercentSpan    Span for varying progress percentage.
    7176     * @param   pfnError        Callback for setting extended error information.
    7277     * @param   pvErrorUser     Opaque parameter for pfnError.
    7378     * @param   ppvBackendData  Opaque state data for this image.
    7479     */
    75     DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData));
     80    DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, unsigned uPercentStart, unsigned uPercentSpan, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData));
     81
     82    /**
     83     * Rename a disk image. Only needs to work as long as the operating
     84     * system's rename file functionality is usable. If an attempt is made to
     85     * rename an image to a location on another disk/filesystem, this function
     86     * may just fail with an appropriate error code (not changing the opened
     87     * image data at all). Also works only on images which actually refer to
     88     * files (and not for raw disk images).
     89     *
     90     * @returns VBox status code.
     91     * @param   pvBackendData   Opaque state data for this image.
     92     * @param   pszFilename     New name of the image file. Guaranteed to be available and
     93     *                          unchanged during the lifetime of this image.
     94     */
     95    DECLR3CALLBACKMEMBER(int, pfnRename, (void *pvBackendData, const char *pszFilename));
    7696
    7797    /**
     
    90110     * @returns VBox status code.
    91111     * @returns VINF_VDI_BLOCK_FREE if this image contains no data for this block.
     112     * @returns VINF_VDI_BLOCK_ZERO if this image contains a zero data block.
    92113     * @param   pvBackendData   Opaque state data for this image.
    93114     * @param   off             Offset to start reading from.
     
    135156
    136157    /**
     158     * Get the version of a disk image.
     159     *
     160     * @returns version of disk image.
     161     * @param   pvBackendData   Opaque state data for this image.
     162     */
     163    DECLR3CALLBACKMEMBER(unsigned, pfnGetVersion, (void *pvBackendData));
     164
     165    /**
    137166     * Get the type information for a disk image.
    138167     *
     
    144173
    145174    /**
    146      * Get the size of a disk image.
    147      *
    148      * @returns size of disk image.
     175     * Get the capacity of a disk image.
     176     *
     177     * @returns size of disk image in bytes.
    149178     * @param   pvBackendData   Opaque state data for this image.
    150179     */
     
    152181
    153182    /**
    154      * Get virtual disk geometry stored in a disk image.
     183     * Get the file size of a disk image.
     184     *
     185     * @returns size of disk image in bytes.
     186     * @param   pvBackendData   Opaque state data for this image.
     187     */
     188    DECLR3CALLBACKMEMBER(uint64_t, pfnGetFileSize, (void *pvBackendData));
     189
     190    /**
     191     * Get virtual disk PCHS geometry stored in a disk image.
    155192     *
    156193     * @returns VBox status code.
    157194     * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the image.
    158195     * @param   pvBackendData   Opaque state data for this image.
    159      * @param   pcCylinders     Where to store the number of cylinders. Never NULL.
    160      * @param   pcHeads         Where to store the number of heads. Never NULL.
    161      * @param   pcSectors       Where to store the number of sectors. Never NULL.
    162      */
    163     DECLR3CALLBACKMEMBER(int, pfnGetGeometry, (void *pvBackendData, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors));
    164 
    165     /**
    166      * Set virtual disk geometry stored in a disk image.
     196     * @param   pPCHSGeometry   Where to store the geometry. Not NULL.
     197     */
     198    DECLR3CALLBACKMEMBER(int, pfnGetPCHSGeometry, (void *pvBackendData, PPDMMEDIAGEOMETRY pPCHSGeometry));
     199
     200    /**
     201     * Set virtual disk PCHS geometry stored in a disk image.
    167202     * Only called if geometry is different than before.
    168203     *
    169204     * @returns VBox status code.
    170205     * @param   pvBackendData   Opaque state data for this image.
    171      * @param   cCylinders      Number of cylinders.
    172      * @param   cHeads          Number of heads.
    173      * @param   cSectors        Number of sectors.
    174      */
    175     DECLR3CALLBACKMEMBER(int, pfnSetGeometry, (void *pvBackendData, unsigned cCylinders, unsigned cHeads, unsigned cSectors));
    176 
    177     /**
    178      * Get virtual disk translation mode stored in a disk image.
     206     * @param   pPCHSGeometry   Where to load the geometry from. Not NULL.
     207     */
     208    DECLR3CALLBACKMEMBER(int, pfnSetPCHSGeometry, (void *pvBackendData, PCPDMMEDIAGEOMETRY pPCHSGeometry));
     209
     210    /**
     211     * Get virtual disk LCHS geometry stored in a disk image.
    179212     *
    180213     * @returns VBox status code.
    181214     * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry present in the image.
    182215     * @param   pvBackendData   Opaque state data for this image.
    183      * @param   penmTranslation Where to store the translation mode. Never NULL.
    184      */
    185     DECLR3CALLBACKMEMBER(int, pfnGetTranslation, (void *pvBackendData, PPDMBIOSTRANSLATION penmTranslation));
    186 
    187     /**
    188      * Set virtual disk translation mode stored in a disk image.
    189      * Only called if translation mode is different than before.
    190      *
    191      * @returns VBox status code.
    192      * @param   pvBackendData   Opaque state data for this image.
    193      * @param   enmTranslation  New translation mode.
    194      */
    195     DECLR3CALLBACKMEMBER(int, pfnSetTranslation, (void *pvBackendData, PDMBIOSTRANSLATION enmTranslation));
     216     * @param   pLCHSGeometry   Where to store the geometry. Not NULL.
     217     */
     218    DECLR3CALLBACKMEMBER(int, pfnGetLCHSGeometry, (void *pvBackendData, PPDMMEDIAGEOMETRY pLCHSGeometry));
     219
     220    /**
     221     * Set virtual disk LCHS geometry stored in a disk image.
     222     * Only called if geometry is different than before.
     223     *
     224     * @returns VBox status code.
     225     * @param   pvBackendData   Opaque state data for this image.
     226     * @param   pLCHSGeometry   Where to load the geometry from. Not NULL.
     227     */
     228    DECLR3CALLBACKMEMBER(int, pfnSetLCHSGeometry, (void *pvBackendData, PCPDMMEDIAGEOMETRY pLCHSGeometry));
     229
     230    /**
     231     * Get the image flags of a disk image.
     232     *
     233     * @returns image flags of disk image.
     234     * @param   pvBackendData   Opaque state data for this image.
     235     */
     236    DECLR3CALLBACKMEMBER(unsigned, pfnGetImageFlags, (void *pvBackendData));
    196237
    197238    /**
     
    288329    DECLR3CALLBACKMEMBER(int, pfnSetParentUuid, (void *pvBackendData, PCRTUUID pUuid));
    289330
    290 } VBOXHDDBACKEND, *PVBOXHDDBACKEND;
     331    /**
     332     * Dump information about a disk image.
     333     *
     334     * @param   pvBackendData   Opaque state data for this image.
     335     */
     336    DECLR3CALLBACKMEMBER(void, pfnDump, (void *pvBackendData));
     337
     338} VBOXHDDBACKEND;
     339
     340/** Pointer to VD backend. */
     341typedef VBOXHDDBACKEND *PVBOXHDDBACKEND;
     342
     343/** Constant pointer to VD backend. */
     344typedef const VBOXHDDBACKEND *PCVBOXHDDBACKEND;
    291345
    292346/** Initialization entry point. */
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r5999 r6291  
    6060
    6161/**
    62  * Get stored media geometry - BIOS property.
    63  *
    64  * @see PDMIMEDIA::pfnBiosGetGeometry for details.
    65  */
    66 static DECLCALLBACK(int) vdiBiosGetGeometry(PPDMIMEDIA pInterface, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
    67 {
    68     PVDIDISK pData = PDMIMEDIA_2_VDIDISK(pInterface);
    69     int rc = VDIDiskGetGeometry(pData, pcCylinders, pcHeads, pcSectors);
     62 * Get stored media PCHS geometry - BIOS property.
     63 *
     64 * @see PDMIMEDIA::pfnBiosGetPCHSGeometry for details.
     65 */
     66static DECLCALLBACK(int) vdiBiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
     67{
     68    LogFlow(("%s: returns VERR_NOT_IMPLEMENTED\n", __FUNCTION__));
     69    return VERR_NOT_IMPLEMENTED;
     70}
     71
     72
     73/**
     74 * Set stored media PCHS geometry - BIOS property.
     75 *
     76 * @see PDMIMEDIA::pfnBiosSetPCHSGeometry for details.
     77 */
     78static DECLCALLBACK(int) vdiBiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
     79{
     80    LogFlow(("%s: returns VERR_NOT_IMPLEMENTED\n", __FUNCTION__));
     81    return VERR_NOT_IMPLEMENTED;
     82}
     83
     84
     85/**
     86 * Get stored media LCHS geometry - BIOS property.
     87 *
     88 * @see PDMIMEDIA::pfnBiosGetLCHSGeometry for details.
     89 */
     90static DECLCALLBACK(int) vdiBiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
     91{
     92    PVDIDISK pData = PDMIMEDIA_2_VDIDISK(pInterface);
     93    int rc = VDIDiskGetLCHSGeometry(pData, pLCHSGeometry);
    7094    if (VBOX_SUCCESS(rc))
    7195    {
    72         LogFlow(("vdiBiosGetGeometry: returns VINF_SUCCESS\n"));
     96        LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
    7397        return VINF_SUCCESS;
    7498    }
    75     Log(("vdiBiosGetGeometry: The Bios geometry data was not available.\n"));
     99    Log(("%s: The Bios geometry data was not available.\n", __FUNCTION__));
    76100    return VERR_PDM_GEOMETRY_NOT_SET;
    77101}
     
    79103
    80104/**
    81  * Set stored media geometry - BIOS property.
    82  *
    83  * @see PDMIMEDIA::pfnBiosSetGeometry for details.
    84  */
    85 static DECLCALLBACK(int) vdiBiosSetGeometry(PPDMIMEDIA pInterface, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
    86 {
    87     PVDIDISK pData = PDMIMEDIA_2_VDIDISK(pInterface);
    88     int rc = VDIDiskSetGeometry(pData, cCylinders, cHeads, cSectors);
    89     LogFlow(("vdiBiosSetGeometry: returns %Vrc (%d,%d,%d)\n", rc, cCylinders, cHeads, cSectors));
     105 * Set stored media LCHS geometry - BIOS property.
     106 *
     107 * @see PDMIMEDIA::pfnBiosSetLCHSGeometry for details.
     108 */
     109static DECLCALLBACK(int) vdiBiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
     110{
     111    PVDIDISK pData = PDMIMEDIA_2_VDIDISK(pInterface);
     112    int rc = VDIDiskSetLCHSGeometry(pData, pLCHSGeometry);
     113    LogFlow(("%s: returns %Vrc (%d,%d,%d)\n", __FUNCTION__, rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    90114    return rc;
    91115}
     
    161185    LogFlow(("vdiIsReadOnly: returns %d\n", VDIDiskIsReadOnly(pData)));
    162186    return VDIDiskIsReadOnly(pData);
    163 }
    164 
    165 
    166 /** @copydoc PDMIMEDIA::pfnBiosGetTranslation */
    167 static DECLCALLBACK(int) vdiBiosGetTranslation(PPDMIMEDIA pInterface,
    168                                                PPDMBIOSTRANSLATION penmTranslation)
    169 {
    170     PVDIDISK pData = PDMIMEDIA_2_VDIDISK(pInterface);
    171     int rc = VDIDiskGetTranslation(pData, penmTranslation);
    172     LogFlow(("vdiBiosGetTranslation: returns %Vrc (%d)\n", rc, *penmTranslation));
    173     return rc;
    174 }
    175 
    176 
    177 /** @copydoc PDMIMEDIA::pfnBiosSetTranslation */
    178 static DECLCALLBACK(int) vdiBiosSetTranslation(PPDMIMEDIA pInterface,
    179                                                PDMBIOSTRANSLATION enmTranslation)
    180 {
    181     PVDIDISK pData = PDMIMEDIA_2_VDIDISK(pInterface);
    182     int rc = VDIDiskSetTranslation(pData, enmTranslation);
    183     LogFlow(("vdiBiosSetTranslation: returns %Vrc (%d)\n", rc, enmTranslation));
    184     return rc;
    185187}
    186188
     
    301303    pData->IMedia.pfnGetUuid            = vdiGetUuid;
    302304    pData->IMedia.pfnIsReadOnly         = vdiIsReadOnly;
    303     pData->IMedia.pfnBiosGetGeometry    = vdiBiosGetGeometry;
    304     pData->IMedia.pfnBiosSetGeometry    = vdiBiosSetGeometry;
    305     pData->IMedia.pfnBiosGetTranslation = vdiBiosGetTranslation;
    306     pData->IMedia.pfnBiosSetTranslation = vdiBiosSetTranslation;
     305    pData->IMedia.pfnBiosGetPCHSGeometry = vdiBiosGetPCHSGeometry;
     306    pData->IMedia.pfnBiosSetPCHSGeometry = vdiBiosSetPCHSGeometry;
     307    pData->IMedia.pfnBiosGetLCHSGeometry = vdiBiosGetLCHSGeometry;
     308    pData->IMedia.pfnBiosSetLCHSGeometry = vdiBiosSetLCHSGeometry;
    307309
    308310    /*
  • trunk/src/VBox/Devices/Storage/VDICore.cpp

    r5999 r6291  
    144144
    145145    /* Mark the geometry not-calculated. */
    146     pHeader->u.v1.Geometry.cCylinders = 0;
    147     pHeader->u.v1.Geometry.cHeads = 0;
    148     pHeader->u.v1.Geometry.cSectors = 0;
    149     pHeader->u.v1.Geometry.cbSector = VDI_GEOMETRY_SECTOR_SIZE;
    150     pHeader->u.v1.u32Translation = PDMBIOSTRANSLATION_AUTO;
     146    pHeader->u.v1.LCHSGeometry.cCylinders = 0;
     147    pHeader->u.v1.LCHSGeometry.cHeads = 0;
     148    pHeader->u.v1.LCHSGeometry.cSectors = 0;
     149    pHeader->u.v1.LCHSGeometry.cbSector = VDI_GEOMETRY_SECTOR_SIZE;
     150    pHeader->u.v1.u32Dummy = 0;
    151151
    152152    pHeader->u.v1.cbDisk = cbDisk;
     
    246246    }
    247247
    248     if ((getImageGeometry(pHeader))->cbSector != VDI_GEOMETRY_SECTOR_SIZE)
     248    if ((getImageLCHSGeometry(pHeader))->cbSector != VDI_GEOMETRY_SECTOR_SIZE)
    249249    {
    250250        LogRel(("VDI: wrong sector size (%d != %d)\n",
    251                (getImageGeometry(pHeader))->cbSector, VDI_GEOMETRY_SECTOR_SIZE));
     251               (getImageLCHSGeometry(pHeader))->cbSector, VDI_GEOMETRY_SECTOR_SIZE));
    252252        fFailed = true;
    253253    }
     
    22662266                  0);
    22672267    setImageBlocksAllocated(&Header, getImageBlocksAllocated(&pImage->Header));
    2268     *getImageGeometry(&Header) = *getImageGeometry(&pImage->Header);
    2269     setImageTranslation(&Header, getImageTranslation(&pImage->Header));
     2268    *getImageLCHSGeometry(&Header) = *getImageLCHSGeometry(&pImage->Header);
    22702269    *getImageCreationUUID(&Header) = *getImageCreationUUID(&pImage->Header);
    22712270    *getImageModificationUUID(&Header) = *getImageModificationUUID(&pImage->Header);
     
    28012800    }
    28022801
    2803     AssertMsgFailed(("No one disk image is opened!\n"));
     2802    AssertMsgFailed(("No disk image is opened!\n"));
    28042803    return true;
    28052804}
     
    28232822    }
    28242823
    2825     AssertMsgFailed(("No one disk image is opened!\n"));
     2824    AssertMsgFailed(("No disk image is opened!\n"));
    28262825    return 0;
    28272826}
     
    28452844    }
    28462845
    2847     AssertMsgFailed(("No one disk image is opened!\n"));
     2846    AssertMsgFailed(("No disk image is opened!\n"));
    28482847    return 0;
    28492848}
    28502849
    28512850/**
    2852  * Get virtual disk geometry stored in image file.
     2851 * Get virtual disk LCHS geometry stored in image file.
    28532852 *
    28542853 * @returns VBox status code.
     
    28562855 * @returns VERR_VDI_GEOMETRY_NOT_SET if no geometry has been setted.
    28572856 * @param   pDisk           Pointer to VDI HDD container.
    2858  * @param   pcCylinders     Where to store the number of cylinders. NULL is ok.
    2859  * @param   pcHeads         Where to store the number of heads. NULL is ok.
    2860  * @param   pcSectors       Where to store the number of sectors. NULL is ok.
    2861  */
    2862 VBOXDDU_DECL(int) VDIDiskGetGeometry(PVDIDISK pDisk, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors)
     2857 * @param   pLCHSGeometry   Where to store LCHS geometry. Not NULL.
     2858 */
     2859VBOXDDU_DECL(int) VDIDiskGetLCHSGeometry(PVDIDISK pDisk, PPDMMEDIAGEOMETRY pLCHSGeometry)
    28632860{
    28642861    /* sanity check */
     
    28692866    {
    28702867        int rc = VINF_SUCCESS;
    2871         PVDIDISKGEOMETRY pGeometry = getImageGeometry(&pDisk->pBase->Header);
    2872         LogFlow(("VDIDiskGetGeometry: C/H/S = %u/%u/%u\n",
    2873                  pGeometry->cCylinders, pGeometry->cHeads, pGeometry->cSectors));
     2868        PVDIDISKGEOMETRY pGeometry = getImageLCHSGeometry(&pDisk->pBase->Header);
     2869        LogFlow(("%s: C/H/S = %u/%u/%u\n",
     2870                 __FUNCTION__, pGeometry->cCylinders, pGeometry->cHeads, pGeometry->cSectors));
    28742871        if (    pGeometry->cCylinders > 0
    28752872            &&  pGeometry->cHeads > 0
    28762873            &&  pGeometry->cSectors > 0)
    28772874        {
    2878             if (pcCylinders)
    2879                 *pcCylinders = pGeometry->cCylinders;
    2880             if (pcHeads)
    2881                 *pcHeads = pGeometry->cHeads;
    2882             if (pcSectors)
    2883                 *pcSectors = pGeometry->cSectors;
     2875            pLCHSGeometry->cCylinders = pGeometry->cCylinders;
     2876            pLCHSGeometry->cHeads = pGeometry->cHeads;
     2877            pLCHSGeometry->cSectors = pGeometry->cSectors;
    28842878        }
    28852879        else
    28862880            rc = VERR_VDI_GEOMETRY_NOT_SET;
    28872881
    2888         LogFlow(("VDIDiskGetGeometry: returns %Vrc\n", rc));
     2882        LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    28892883        return rc;
    28902884    }
    28912885
    2892     AssertMsgFailed(("No one disk image is opened!\n"));
     2886    AssertMsgFailed(("No disk image is opened!\n"));
    28932887    return VERR_VDI_NOT_OPENED;
    28942888}
    28952889
    28962890/**
    2897  * Store virtual disk geometry into base image file of HDD container.
     2891 * Store virtual disk LCHS geometry into base image file of HDD container.
    28982892 *
    28992893 * Note that in case of unrecoverable error all images of HDD container will be closed.
     
    29022896 * @returns VERR_VDI_NOT_OPENED if no one VDI image is opened in HDD container.
    29032897 * @param   pDisk           Pointer to VDI HDD container.
    2904  * @param   cCylinders      Number of cylinders.
    2905  * @param   cHeads          Number of heads.
    2906  * @param   cSectors        Number of sectors.
    2907  */
    2908 VBOXDDU_DECL(int) VDIDiskSetGeometry(PVDIDISK pDisk, unsigned cCylinders, unsigned cHeads, unsigned cSectors)
    2909 {
    2910     LogFlow(("VDIDiskSetGeometry: C/H/S = %u/%u/%u\n", cCylinders, cHeads, cSectors));
     2898 * @param   pLCHSGeometry   Where to load LCHS geometry from. Not NULL.
     2899 */
     2900VBOXDDU_DECL(int) VDIDiskSetLCHSGeometry(PVDIDISK pDisk, PCPDMMEDIAGEOMETRY pLCHSGeometry)
     2901{
     2902    LogFlow(("%s: C/H/S = %u/%u/%u\n", __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
    29112903    /* sanity check */
    29122904    Assert(pDisk);
     
    29152907    if (pDisk->pBase)
    29162908    {
    2917         PVDIDISKGEOMETRY pGeometry = getImageGeometry(&pDisk->pBase->Header);
    2918         pGeometry->cCylinders = cCylinders;
    2919         pGeometry->cHeads = cHeads;
    2920         pGeometry->cSectors = cSectors;
     2909        PVDIDISKGEOMETRY pGeometry = getImageLCHSGeometry(&pDisk->pBase->Header);
     2910        pGeometry->cCylinders = pLCHSGeometry->cCylinders;
     2911        pGeometry->cHeads = pLCHSGeometry->cHeads;
     2912        pGeometry->cSectors = pLCHSGeometry->cSectors;
    29212913        pGeometry->cbSector = VDI_GEOMETRY_SECTOR_SIZE;
    29222914
    29232915        /* Update header information in base image file. */
    29242916        int rc = vdiUpdateReadOnlyHeader(pDisk->pBase);
    2925         LogFlow(("VDIDiskSetGeometry: returns %Vrc\n", rc));
     2917        LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
    29262918        return rc;
    29272919    }
    29282920
    2929     AssertMsgFailed(("No one disk image is opened!\n"));
    2930     return VERR_VDI_NOT_OPENED;
    2931 }
    2932 
    2933 /**
    2934  * Get virtual disk translation mode stored in image file.
    2935  *
    2936  * @returns VBox status code.
    2937  * @returns VERR_VDI_NOT_OPENED if no one VDI image is opened in HDD container.
    2938  * @param   pDisk           Pointer to VDI HDD container.
    2939  * @param   penmTranslation Where to store the translation mode (see pdm.h).
    2940  */
    2941 VBOXDDU_DECL(int) VDIDiskGetTranslation(PVDIDISK pDisk, PPDMBIOSTRANSLATION penmTranslation)
    2942 {
    2943     /* sanity check */
    2944     Assert(pDisk);
    2945     AssertMsg(pDisk->u32Signature == VDIDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    2946     Assert(penmTranslation);
    2947 
    2948     if (pDisk->pBase)
    2949     {
    2950         *penmTranslation = getImageTranslation(&pDisk->pBase->Header);
    2951         LogFlow(("VDIDiskGetTranslation: translation=%d\n", *penmTranslation));
    2952         return VINF_SUCCESS;
    2953     }
    2954 
    2955     AssertMsgFailed(("No one disk image is opened!\n"));
    2956     return VERR_VDI_NOT_OPENED;
    2957 }
    2958 
    2959 /**
    2960  * Store virtual disk translation mode into base image file of HDD container.
    2961  *
    2962  * Note that in case of unrecoverable error all images of HDD container will be closed.
    2963  *
    2964  * @returns VBox status code.
    2965  * @returns VERR_VDI_NOT_OPENED if no one VDI image is opened in HDD container.
    2966  * @param   pDisk           Pointer to VDI HDD container.
    2967  * @param   enmTranslation  Translation mode (see pdm.h).
    2968  */
    2969 VBOXDDU_DECL(int) VDIDiskSetTranslation(PVDIDISK pDisk, PDMBIOSTRANSLATION enmTranslation)
    2970 {
    2971     LogFlow(("VDIDiskSetTranslation: enmTranslation=%d\n", enmTranslation));
    2972     /* sanity check */
    2973     Assert(pDisk);
    2974     AssertMsg(pDisk->u32Signature == VDIDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    2975 
    2976     if (pDisk->pBase)
    2977     {
    2978         setImageTranslation(&pDisk->pBase->Header, enmTranslation);
    2979 
    2980         /* Update header information in base image file. */
    2981         int rc = vdiUpdateReadOnlyHeader(pDisk->pBase);
    2982         LogFlow(("VDIDiskSetTranslation: returns %Vrc\n", rc));
    2983         return rc;
    2984     }
    2985 
    2986     AssertMsgFailed(("No one disk image is opened!\n"));
     2921    AssertMsgFailed(("No disk image is opened!\n"));
    29872922    return VERR_VDI_NOT_OPENED;
    29882923}
     
    35283463    if (!pImage)
    35293464    {
    3530         AssertMsgFailed(("No one disk image is opened!\n"));
     3465        AssertMsgFailed(("No disk image is opened!\n"));
    35313466        return VERR_VDI_NOT_OPENED;
    35323467    }
     
    35973532    if (!pDisk->pLast)
    35983533    {
    3599         AssertMsgFailed(("No one disk image is opened!\n"));
     3534        AssertMsgFailed(("No disk image is opened!\n"));
    36003535        return VERR_VDI_NOT_OPENED;
    36013536    }
     
    36463581                getImageBlocksOffset(&pImage->Header),
    36473582                getImageDataOffset(&pImage->Header));
    3648     PVDIDISKGEOMETRY pg = getImageGeometry(&pImage->Header);
    3649     RTLogPrintf("Header: Geometry: C/H/S=%u/%u/%u cbSector=%u Mode=%u\n",
    3650                 pg->cCylinders, pg->cHeads, pg->cSectors, pg->cbSector,
    3651                 getImageTranslation(&pImage->Header));
     3583    PVDIDISKGEOMETRY pg = getImageLCHSGeometry(&pImage->Header);
     3584    RTLogPrintf("Header: Geometry: C/H/S=%u/%u/%u cbSector=%u\n",
     3585                pg->cCylinders, pg->cHeads, pg->cSectors, pg->cbSector);
    36523586    RTLogPrintf("Header: uuidCreation={%Vuuid}\n", getImageCreationUUID(&pImage->Header));
    36533587    RTLogPrintf("Header: uuidModification={%Vuuid}\n", getImageModificationUUID(&pImage->Header));
  • trunk/src/VBox/Devices/Storage/VDICore.h

    r5999 r6291  
    106106    char            szComment[VDI_IMAGE_COMMENT_SIZE];
    107107    /** Image geometry. */
    108     VDIDISKGEOMETRY Geometry;
     108    VDIDISKGEOMETRY LCHSGeometry;
    109109    /** Size of disk (in bytes). */
    110110    uint64_t        cbDisk;
     
    146146    uint32_t        offData;
    147147    /** Image geometry. */
    148     VDIDISKGEOMETRY Geometry;
    149     /** BIOS HDD translation mode, see PDMBIOSTRANSLATION. */
    150     uint32_t        u32Translation;
     148    VDIDISKGEOMETRY LCHSGeometry;
     149    /** Was BIOS HDD translation mode, now unused. */
     150    uint32_t        u32Dummy;
    151151    /** Size of disk (in bytes). */
    152152    uint64_t        cbDisk;
     
    272272}
    273273
    274 DECLINLINE(PVDIDISKGEOMETRY) getImageGeometry(PVDIHEADER ph)
    275 {
    276     switch (GET_MAJOR_HEADER_VERSION(ph))
    277     {
    278         case 0: return &ph->u.v0.Geometry;
    279         case 1: return &ph->u.v1.Geometry;
     274DECLINLINE(PVDIDISKGEOMETRY) getImageLCHSGeometry(PVDIHEADER ph)
     275{
     276    switch (GET_MAJOR_HEADER_VERSION(ph))
     277    {
     278        case 0: return &ph->u.v0.LCHSGeometry;
     279        case 1: return &ph->u.v1.LCHSGeometry;
    280280    }
    281281    AssertFailed();
    282282    return NULL;
    283 }
    284 
    285 DECLINLINE(PDMBIOSTRANSLATION) getImageTranslation(PVDIHEADER ph)
    286 {
    287     switch (GET_MAJOR_HEADER_VERSION(ph))
    288     {
    289         case 0: return PDMBIOSTRANSLATION_AUTO;
    290         case 1: return (PDMBIOSTRANSLATION)ph->u.v1.u32Translation;
    291     }
    292     AssertFailed();
    293     return PDMBIOSTRANSLATION_NONE;
    294 }
    295 
    296 DECLINLINE(void) setImageTranslation(PVDIHEADER ph, PDMBIOSTRANSLATION enmTranslation)
    297 {
    298     switch (GET_MAJOR_HEADER_VERSION(ph))
    299     {
    300         case 0:                                                     return;
    301         case 1: ph->u.v1.u32Translation = (uint32_t)enmTranslation; return;
    302     }
    303     AssertFailed();
    304283}
    305284
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r5999 r6291  
    3636*   Constants And Macros, Structures and Typedefs                              *
    3737*******************************************************************************/
     38
     39/** VMDK descriptor DDB entry for PCHS cylinders. */
     40#define VMDK_DDB_GEO_PCHS_CYLINDERS "ddb.geometry.cylinders"
     41
     42/** VMDK descriptor DDB entry for PCHS heads. */
     43#define VMDK_DDB_GEO_PCHS_HEADS "ddb.geometry.heads"
     44
     45/** VMDK descriptor DDB entry for PCHS sectors. */
     46#define VMDK_DDB_GEO_PCHS_SECTORS "ddb.geometry.sectors"
     47
     48/** VMDK descriptor DDB entry for LCHS cylinders. */
     49#define VMDK_DDB_GEO_LCHS_CYLINDERS "ddb.geometry.biosCylinders"
     50
     51/** VMDK descriptor DDB entry for LCHS heads. */
     52#define VMDK_DDB_GEO_LCHS_HEADS "ddb.geometry.biosHeads"
     53
     54/** VMDK descriptor DDB entry for LCHS sectors. */
     55#define VMDK_DDB_GEO_LCHS_SECTORS "ddb.geometry.biosSectors"
    3856
    3957/**
     
    6785#pragma pack()
    6886
     87/** VMDK capacity for a single chunk when 2G splitting is turned on. Should be
     88 * divisible by the default grain size (64K) */
     89#define VMDK_2G_SPLIT_SIZE (2047 * 1024 * 1024)
     90
    6991
    7092#ifdef VBOX_WITH_VMDK_ESX
     
    89111    uint32_t    freeSector;
    90112    /* The spec incompletely documents quite a few further fields, but states
    91      * that they are not used by the current format. Replace them by padding. */
     113     * that they are unused by the current format. Replace them by padding. */
    92114    char        reserved1[1604];
    93115    uint32_t    savedGeneration;
     
    274296typedef struct VMDKIMAGE
    275297{
     298    /** Pointer to the image extents. */
    276299    PVMDKEXTENT     pExtents;
     300    /** Number of image extents. */
    277301    unsigned        cExtents;
    278302
     
    295319    /** Total size of the image. */
    296320    uint64_t        cbSize;
    297     /** BIOS translation mode. */
    298     PDMBIOSTRANSLATION enmTranslation;
    299     /** Physical geometry of this image, cylinders. */
    300     uint32_t        cCylinders;
    301     /** Physical geometry of this image, heads. */
    302     uint32_t        cHeads;
    303     /** Physical geometry of this image, sectors. */
    304     uint32_t        cSectors;
     321    /** Physical geometry of this image. */
     322    PDMMEDIAGEOMETRY   PCHSGeometry;
     323    /** Logical geometry of this image. */
     324    PDMMEDIAGEOMETRY   LCHSGeometry;
    305325    /** Image UUID. */
    306326    RTUUID          ImageUuid;
     
    310330    RTUUID          ParentUuid;
    311331
    312     /** Pointer to the grain table cache, if this image contains sparse extents. */
     332    /** Pointer to grain table cache, if this image contains sparse extents. */
    313333    PVMDKGTCACHE    pGTCache;
    314334    /** Pointer to the descriptor (NULL if no separate descriptor file). */
     
    342362static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
    343363
    344 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData);
    345 static int vmdkClose(void *pBackendData, bool fDelete);
    346 
    347364
    348365DECLINLINE(int) vmdkError(PVMDKIMAGE pImage, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
     
    350367    va_list va;
    351368    va_start(va, pszFormat);
    352     pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
     369    if (pImage->pfnError)
     370        pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
    353371    va_end(va);
    354372    return rc;
     
    439457        }
    440458
    441         for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD; i < pExtent->cGDEntries; i++, pGDTmp++, pRGDTmp++)
     459        for (i = 0, pGDTmp = pGD, pRGDTmp = pRGD;
     460             i < pExtent->cGDEntries;
     461             i++, pGDTmp++, pRGDTmp++)
    442462        {
    443463            /* If no grain table is allocated skip the entry. */
     
    491511}
    492512
    493 static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector, bool fPreAlloc)
     513static int vmdkCreateGrainDirectory(PVMDKEXTENT pExtent, uint64_t uStartSector,
     514                                    bool fPreAlloc)
    494515{
    495516    int rc = VINF_SUCCESS;
     
    539560            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    540561            /* Write the redundant grain directory entry to disk. */
    541             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     562            rc = RTFileWriteAt(pExtent->File,
     563                               VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
     564                               &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    542565            if (VBOX_FAILURE(rc))
    543566                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
     
    551574            uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
    552575            /* Write the grain directory entry to disk. */
    553             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     576            rc = RTFileWriteAt(pExtent->File,
     577                               VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
     578                               &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    554579            if (VBOX_FAILURE(rc))
    555580                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
     
    579604}
    580605
    581 static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr, char **ppszUnquoted, char **ppszNext)
     606static int vmdkStringUnquote(PVMDKIMAGE pImage, const char *pszStr,
     607                             char **ppszUnquoted, char **ppszNext)
    582608{
    583609    char *pszQ;
     
    632658        if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
    633659        {
    634             /* Key matches, check if there is a '=' (preceded by whitespace). */
     660            /* Key matches, check for a '=' (preceded by whitespace). */
    635661            pszValue = pDescriptor->aLines[uStart] + cbKey;
    636662            while (*pszValue == ' ' || *pszValue == '\t')
     
    659685        if (!strncmp(pDescriptor->aLines[uStart], pszKey, cbKey))
    660686        {
    661             /* Key matches, check if there is a '=' (preceded by whitespace). */
     687            /* Key matches, check for a '=' (preceded by whitespace). */
    662688            pszTmp = pDescriptor->aLines[uStart] + cbKey;
    663689            while (*pszTmp == ' ' || *pszTmp == '\t')
     
    715741    else
    716742    {
    717         /* Key doesn't exist, append it after the last entry in this category. */
     743        /* Key doesn't exist, append after the last entry in this category. */
    718744        if (!pszValue)
    719745        {
     
    765791    const char *pszValue;
    766792
    767     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, &pszValue))
     793    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
     794                        &pszValue))
    768795        return VERR_VDI_VALUE_NOT_FOUND;
    769796    return RTStrToUInt32Ex(pszValue, NULL, 10, puValue);
     
    776803    char *pszValueUnquoted;
    777804
    778     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey, &pszValue))
     805    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDesc, pszKey,
     806                        &pszValue))
    779807        return VERR_VDI_VALUE_NOT_FOUND;
    780808    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    793821    if (VBOX_FAILURE(rc))
    794822        return rc;
    795     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey, pszValueQuoted);
     823    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, pszKey,
     824                        pszValueQuoted);
    796825    RTStrFree(pszValueQuoted);
    797826    return rc;
    798827}
    799828
    800 static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor)
     829static void vmdkDescExtRemoveDummy(PVMDKIMAGE pImage,
     830                                   PVMDKDESCRIPTOR pDescriptor)
    801831{
    802832    unsigned uEntry = pDescriptor->uFirstExtent;
     
    807837
    808838    cbDiff = strlen(pDescriptor->aLines[uEntry]) + 1;
    809     /* Move everything including the \0 in the entry marking the end of buffer. */
     839    /* Move everything including \0 in the entry marking the end of buffer. */
    810840    memmove(pDescriptor->aLines[uEntry], pDescriptor->aLines[uEntry + 1],
    811841            pDescriptor->aLines[pDescriptor->cLines] - pDescriptor->aLines[uEntry + 1] + 1);
     
    902932    char *pszValueUnquoted;
    903933
    904     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
     934    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
     935                        &pszValue))
    905936        return VERR_VDI_VALUE_NOT_FOUND;
    906937    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    917948    char *pszValueUnquoted;
    918949
    919     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
     950    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
     951                        &pszValue))
    920952        return VERR_VDI_VALUE_NOT_FOUND;
    921953    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    933965    char *pszValueUnquoted;
    934966
    935     if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey, &pszValue))
     967    if (!vmdkDescGetStr(pDescriptor, pDescriptor->uFirstDDB, pszKey,
     968                        &pszValue))
    936969        return VERR_VDI_VALUE_NOT_FOUND;
    937970    int rc = vmdkStringUnquote(pImage, pszValue, &pszValueUnquoted, NULL);
     
    943976}
    944977
    945 static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, const char *pszVal)
     978static int vmdkDescDDBSetStr(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     979                             const char *pszKey, const char *pszVal)
    946980{
    947981    int rc;
     
    956990    else
    957991        pszValQuoted = NULL;
    958     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValQuoted);
     992    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
     993                        pszValQuoted);
    959994    if (pszValQuoted)
    960995        RTStrFree(pszValQuoted);
     
    962997}
    963998
    964 static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, PCRTUUID pUuid)
     999static int vmdkDescDDBSetUuid(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     1000                              const char *pszKey, PCRTUUID pUuid)
    9651001{
    9661002    char *pszUuid;
     
    9691005    if (VBOX_FAILURE(rc))
    9701006        return rc;
    971     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszUuid);
     1007    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
     1008                        pszUuid);
    9721009    RTStrFree(pszUuid);
    9731010    return rc;
    9741011}
    9751012
    976 int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor, const char *pszKey, uint32_t uValue)
     1013int vmdkDescDDBSetU32(PVMDKIMAGE pImage, PVMDKDESCRIPTOR pDescriptor,
     1014                      const char *pszKey, uint32_t uValue)
    9771015{
    9781016    char *pszValue;
     
    9811019    if (VBOX_FAILURE(rc))
    9821020        return rc;
    983     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey, pszValue);
     1021    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDDB, pszKey,
     1022                        pszValue);
    9841023    RTStrFree(pszValue);
    9851024    return rc;
    9861025}
    9871026
    988 static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     1027static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
     1028                                    size_t cbDescData,
     1029                                    PVMDKDESCRIPTOR pDescriptor)
    9891030{
    9901031    int rc = VINF_SUCCESS;
     
    11011142}
    11021143
    1103 static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
     1144static int vmdkDescSetPCHSGeometry(PVMDKIMAGE pImage,
     1145                                   PCPDMMEDIAGEOMETRY pPCHSGeometry)
     1146{
     1147    int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1148                           VMDK_DDB_GEO_PCHS_CYLINDERS,
     1149                           pPCHSGeometry->cCylinders);
     1150    if (VBOX_FAILURE(rc))
     1151        return rc;
     1152    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1153                           VMDK_DDB_GEO_PCHS_HEADS,
     1154                           pPCHSGeometry->cHeads);
     1155    if (VBOX_FAILURE(rc))
     1156        return rc;
     1157    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1158                           VMDK_DDB_GEO_PCHS_SECTORS,
     1159                           pPCHSGeometry->cSectors);
     1160    return rc;
     1161}
     1162
     1163static int vmdkDescSetLCHSGeometry(PVMDKIMAGE pImage,
     1164                                   PCPDMMEDIAGEOMETRY pLCHSGeometry)
     1165{
     1166    int rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1167                           VMDK_DDB_GEO_LCHS_CYLINDERS,
     1168                           pLCHSGeometry->cCylinders);
     1169    if (VBOX_FAILURE(rc))
     1170        return rc;
     1171    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1172                           VMDK_DDB_GEO_LCHS_HEADS,
     1173                           pLCHSGeometry->cHeads);
     1174    if (VBOX_FAILURE(rc))
     1175        return rc;
     1176    rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
     1177                           VMDK_DDB_GEO_LCHS_SECTORS,
     1178                           pLCHSGeometry->cSectors);
     1179    return rc;
     1180}
     1181
     1182static int vmdkCreateDescriptor(PVMDKIMAGE pImage, char *pDescData,
     1183                                size_t cbDescData, PVMDKDESCRIPTOR pDescriptor)
    11041184{
    11051185    int rc;
     
    11531233    char szBuf[9];
    11541234    RTStrPrintf(szBuf, sizeof(szBuf), "%08x", RTRandU32());
    1155     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "CID", szBuf);
    1156     if (VBOX_FAILURE(rc))
    1157         goto out;
    1158     rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc, "parentCID", "ffffffff");
     1235    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
     1236                        "CID", szBuf);
     1237    if (VBOX_FAILURE(rc))
     1238        goto out;
     1239    rc = vmdkDescSetStr(pImage, pDescriptor, pDescriptor->uFirstDesc,
     1240                        "parentCID", "ffffffff");
    11591241    if (VBOX_FAILURE(rc))
    11601242        goto out;
     
    11681250}
    11691251
    1170 static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData, size_t cbDescData)
     1252static int vmdkParseDescriptor(PVMDKIMAGE pImage, char *pDescData,
     1253                               size_t cbDescData)
    11711254{
    11721255    int rc;
     
    11741257    unsigned uLine;
    11751258
    1176     rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData, &pImage->Descriptor);
     1259    rc = vmdkPreprocessDescriptor(pImage, pDescData, cbDescData,
     1260                                  &pImage->Descriptor);
    11771261    if (VBOX_FAILURE(rc))
    11781262        return rc;
     
    13181402    }
    13191403
     1404    /* Determine PCHS geometry (autogenerate if necessary). */
    13201405    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1321                            "ddb.geometry.cylinders", &pImage->cCylinders);
    1322     if (VBOX_FAILURE(rc))
    1323         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
     1406                           VMDK_DDB_GEO_PCHS_CYLINDERS,
     1407                           &pImage->PCHSGeometry.cCylinders);
     1408    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1409        pImage->PCHSGeometry.cCylinders = 0;
     1410    else if (VBOX_FAILURE(rc))
     1411        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
    13241412    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1325                            "ddb.geometry.heads", &pImage->cHeads);
    1326     if (VBOX_FAILURE(rc))
    1327         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
     1413                           VMDK_DDB_GEO_PCHS_HEADS,
     1414                           &pImage->PCHSGeometry.cHeads);
     1415    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1416        pImage->PCHSGeometry.cHeads = 0;
     1417    else if (VBOX_FAILURE(rc))
     1418        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
    13281419    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
    1329                            "ddb.geometry.sectors", &pImage->cSectors);
    1330     if (VBOX_FAILURE(rc))
    1331         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting CHS geometry from extent description in '%s'"), pImage->pszFilename);
    1332     if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
    1333         pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
    1334     else
    1335         pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;
     1420                           VMDK_DDB_GEO_PCHS_SECTORS,
     1421                           &pImage->PCHSGeometry.cSectors);
     1422    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1423        pImage->PCHSGeometry.cSectors = 0;
     1424    else if (VBOX_FAILURE(rc))
     1425        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting PCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1426    if (    pImage->PCHSGeometry.cCylinders == 0
     1427        ||  pImage->PCHSGeometry.cHeads == 0
     1428        ||  pImage->PCHSGeometry.cHeads > 16
     1429        ||  pImage->PCHSGeometry.cSectors == 0
     1430        ||  pImage->PCHSGeometry.cSectors > 63)
     1431    {
     1432        /* Mark PCHS geometry as not yet valid (can't do the calculation here
     1433         * as the total image size isn't known yet). */
     1434        pImage->PCHSGeometry.cCylinders = 0;
     1435        pImage->PCHSGeometry.cHeads = 16;
     1436        pImage->PCHSGeometry.cSectors = 63;
     1437    }
     1438
     1439    /* Determine LCHS geometry (set to 0 if not specified). */
     1440    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     1441                           VMDK_DDB_GEO_LCHS_CYLINDERS,
     1442                           &pImage->LCHSGeometry.cCylinders);
     1443    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1444        pImage->LCHSGeometry.cCylinders = 0;
     1445    else if (VBOX_FAILURE(rc))
     1446        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1447    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     1448                           VMDK_DDB_GEO_LCHS_HEADS,
     1449                           &pImage->LCHSGeometry.cHeads);
     1450    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1451        pImage->LCHSGeometry.cHeads = 0;
     1452    else if (VBOX_FAILURE(rc))
     1453        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1454    rc = vmdkDescDDBGetU32(pImage, &pImage->Descriptor,
     1455                           VMDK_DDB_GEO_LCHS_SECTORS,
     1456                           &pImage->LCHSGeometry.cSectors);
     1457    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     1458        pImage->LCHSGeometry.cSectors = 0;
     1459    else if (VBOX_FAILURE(rc))
     1460        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error getting LCHS geometry from extent description in '%s'"), pImage->pszFilename);
     1461    if (    pImage->LCHSGeometry.cCylinders == 0
     1462        ||  pImage->LCHSGeometry.cHeads == 0
     1463        ||  pImage->LCHSGeometry.cSectors == 0)
     1464    {
     1465        pImage->LCHSGeometry.cCylinders = 0;
     1466        pImage->LCHSGeometry.cHeads = 0;
     1467        pImage->LCHSGeometry.cSectors = 0;
     1468    }
    13361469
    13371470    /* Get image UUID. */
     
    13601493
    13611494    /* Get image modification UUID. */
    1362     rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor, "ddb.uuid.modification",
     1495    rc = vmdkDescDDBGetUuid(pImage, &pImage->Descriptor,
     1496                            "ddb.uuid.modification",
    13631497                            &pImage->ModificationUuid);
    13641498    if (rc == VERR_VDI_VALUE_NOT_FOUND)
     
    13751509                return rc;
    13761510            rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    1377                                     "ddb.uuid.modification", &pImage->ModificationUuid);
     1511                                    "ddb.uuid.modification",
     1512                                    &pImage->ModificationUuid);
    13781513            if (VBOX_FAILURE(rc))
    13791514                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error storing image modification UUID in descriptor in '%s'"), pImage->pszFilename);
     
    17501885}
    17511886
    1752 static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename, unsigned uOpenFlags)
     1887static int vmdkOpenImage(PVMDKIMAGE pImage, const char *pszFilename,
     1888                         unsigned uOpenFlags)
    17531889{
    17541890    int rc = VINF_SUCCESS;
     
    18601996        }
    18611997
    1862         rc = vmdkParseDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc);
     1998        rc = vmdkParseDescriptor(pImage, pImage->pDescData,
     1999                                 pImage->cbDescAlloc);
    18632000        if (VBOX_FAILURE(rc))
    18642001            goto out;
     
    19242061                        goto out;
    19252062
    1926                     /* Mark the extent as unclean if opened in read-write mode. */
     2063                    /* Mark extent as unclean if opened in read-write mode. */
    19272064                    if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY))
    19282065                    {
     
    19562093    AssertRC(rc);
    19572094
     2095    /* Determine PCHS geometry if not set. */
     2096    if (pImage->PCHSGeometry.cCylinders == 0)
     2097    {
     2098        uint64_t cCylinders =   VMDK_BYTE2SECTOR(pImage->cbSize)
     2099                              / pImage->PCHSGeometry.cHeads
     2100                              / pImage->PCHSGeometry.cSectors;
     2101        pImage->PCHSGeometry.cCylinders = (unsigned)RT_MIN(cCylinders, 16383);
     2102        if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
     2103        {
     2104            rc = vmdkDescSetPCHSGeometry(pImage, &pImage->PCHSGeometry);
     2105            AssertRC(rc);
     2106        }
     2107    }
     2108
    19582109    /* Update the image metadata now in case has changed. */
    19592110    rc = vmdkFlushImage(pImage);
     
    20022153}
    20032154
    2004 static int vmdkCreateImage(PVMDKIMAGE pImage, const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, uint32_t cCylinders, uint32_t cHeads, uint32_t cSectors)
    2005 {
    2006     int rc;
    2007     uint64_t cSectorsPerGDE, cSectorsPerGD;
     2155static int vmdkCreateRawImage(PVMDKIMAGE pImage, const char *pszFilename,
     2156                              const PVBOXHDDRAW pRaw, uint64_t cbSize)
     2157{
     2158    int rc = VINF_SUCCESS;
    20082159    PVMDKEXTENT pExtent;
    20092160
    2010     pImage->uImageFlags = uImageFlags;
    2011     rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc, &pImage->Descriptor);
    2012     if (VBOX_FAILURE(rc))
    2013     {
    2014         rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename);
    2015         goto out;
    2016     }
    2017 
    2018     if (    enmType == VD_IMAGE_TYPE_FIXED
    2019         ||  (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
    2020         ||  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
    2021     {
    2022         /* Fixed images and split images in general have a separate descriptor
    2023          * file. This is the more complicated case, as it requires setting up
    2024          * potentially more than one extent, including filename generation. */
    2025 
    2026         if (    enmType == VD_IMAGE_TYPE_FIXED
    2027             &&  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
    2028         {
    2029             PVBOXHDDRAW pRaw = (PVBOXHDDRAW)(void *)pszComment;
    2030             /* As the comment is misused, zap it so that no garbage comment
    2031              * is set below. */
    2032             pszComment = NULL;
    2033             if (pRaw->fRawDisk)
     2161    if (pRaw->fRawDisk)
     2162    {
     2163        /* Full raw disk access. This requires setting up a descriptor
     2164         * file and open the (flat) raw disk. */
     2165        rc = vmdkCreateExtents(pImage, 1);
     2166        if (VBOX_FAILURE(rc))
     2167            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
     2168        pExtent = &pImage->pExtents[0];
     2169        rc = RTFileOpen(&pImage->File, pszFilename,
     2170                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
     2171        if (VBOX_FAILURE(rc))
     2172            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
     2173
     2174        /* Set up basename for extent description. Cannot use StrDup. */
     2175        size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
     2176        char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
     2177        if (!pszBasename)
     2178            return VERR_NO_MEMORY;
     2179        memcpy(pszBasename, pRaw->pszRawDisk, cbBasename);
     2180        pExtent->pszBasename = pszBasename;
     2181        /* For raw disks the full name is identical to the base name. */
     2182        pExtent->pszFullname = RTStrDup(pszBasename);
     2183        if (!pExtent->pszFullname)
     2184            return VERR_NO_MEMORY;
     2185        pExtent->enmType = VMDKETYPE_FLAT;
     2186        pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
     2187        pExtent->uSectorOffset = 0;
     2188        pExtent->enmAccess = VMDKACCESS_READWRITE;
     2189        pExtent->fMetaDirty = false;
     2190
     2191        /* Open flat image, the raw disk. */
     2192        rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2193                        RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2194        if (VBOX_FAILURE(rc))
     2195            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
     2196    }
     2197    else
     2198    {
     2199        /* Raw partition access. This requires setting up a descriptor
     2200         * file, write the partition information to a flat extent and
     2201         * open all the (flat) raw disk partitions. */
     2202
     2203        /* First pass over the partitions to determine how many
     2204         * extents we need. One partition can require up to 4 extents.
     2205         * One to skip over unpartitioned space, one for the
     2206         * partitioning data, one to skip over unpartitioned space
     2207         * and one for the partition data. */
     2208        unsigned cExtents = 0;
     2209        uint64_t uStart = 0;
     2210        for (unsigned i = 0; i < pRaw->cPartitions; i++)
     2211        {
     2212            PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
     2213            if (pPart->cbPartitionData)
    20342214            {
    2035                 /* Full raw disk access. This requires setting up a descriptor
    2036                  * file and open the (flat) raw disk. */
    2037                 rc = vmdkCreateExtents(pImage, 1);
    2038                 if (VBOX_FAILURE(rc))
    2039                 {
    2040                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
    2041                     goto out;
    2042                 }
    2043                 pExtent = &pImage->pExtents[0];
    2044                 rc = RTFileOpen(&pImage->File, pszFilename,
    2045                                 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
    2046                 if (VBOX_FAILURE(rc))
    2047                 {
    2048                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
    2049                     goto out;
    2050                 }
    2051 
    2052                 /* Set up basename for extent description. Cannot use StrDup. */
    2053                 size_t cbBasename = strlen(pRaw->pszRawDisk) + 1;
    2054                 char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2055                 if (!pszBasename)
    2056                 {
    2057                     rc = VERR_NO_MEMORY;
    2058                     goto out;
    2059                 }
    2060                 memcpy(pszBasename, pRaw->pszRawDisk, cbBasename);
    2061                 pExtent->pszBasename = pszBasename;
    2062                 /* For raw disks the full name is identical to the base name. */
    2063                 pExtent->pszFullname = RTStrDup(pszBasename);
    2064                 if (!pExtent->pszFullname)
    2065                 {
    2066                     rc = VERR_NO_MEMORY;
    2067                     goto out;
    2068                 }
    2069                 pExtent->enmType = VMDKETYPE_FLAT;
    2070                 pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
    2071                 pExtent->uSectorOffset = 0;
    2072                 pExtent->enmAccess = VMDKACCESS_READWRITE;
    2073                 pExtent->fMetaDirty = false;
    2074 
    2075                 pImage->enmImageType = enmType;
    2076                 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "fullDevice");
    2077                 if (VBOX_FAILURE(rc))
    2078                 {
    2079                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
    2080                     goto out;
    2081                 }
    2082 
    2083                 /* Open flat image, the raw disk. */
    2084                 rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2085                                 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2086                 if (VBOX_FAILURE(rc))
    2087                 {
    2088                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
    2089                     goto out;
    2090                 }
     2215                if (uStart > pPart->uPartitionDataStart)
     2216                    return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partitioning information in '%s'"), pszFilename);
     2217                else if (uStart != pPart->uPartitionDataStart)
     2218                    cExtents++;
     2219                uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
     2220                cExtents++;
    20912221            }
    2092             else
     2222            if (pPart->cbPartition)
    20932223            {
    2094                 /* Raw partition access. This requires setting up a descriptor
    2095                  * file, write the partition information to a flat extent and
    2096                  * open all the (flat) raw disk partitions. */
    2097 
    2098                 /* First pass over the partitions to determine how many
    2099                  * extents we need. One partition can require up to 4 extents.
    2100                  * One to skip over unpartitioned space, one for the
    2101                  * partitioning data, one to skip over unpartitioned space
    2102                  * and one for the partition data. */
    2103                 unsigned cExtents = 0;
    2104                 uint64_t uStart = 0;
    2105                 for (unsigned i = 0; i < pRaw->cPartitions; i++)
    2106                 {
    2107                     PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
    2108                     if (pPart->cbPartitionData)
    2109                     {
    2110                         if (uStart > pPart->uPartitionDataStart)
    2111                         {
    2112                             rc = vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partitioning information in '%s'"), pszFilename);
    2113                             goto out;
    2114                         } else if (uStart != pPart->uPartitionDataStart)
    2115                             cExtents++;
    2116                         uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
    2117                         cExtents++;
    2118                     }
    2119                     if (pPart->cbPartition)
    2120                     {
    2121                         if (uStart > pPart->uPartitionStart)
    2122                         {
    2123                             rc = vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partition data in '%s'"), pszFilename);
    2124                             goto out;
    2125                         } else if (uStart != pPart->uPartitionStart)
    2126                             cExtents++;
    2127                         uStart = pPart->uPartitionStart + pPart->cbPartition;
    2128                         cExtents++;
    2129                     }
    2130                 }
    2131                 /* Another extent for filling up the rest of the image. */
    2132                 if (uStart != cbSize)
     2224                if (uStart > pPart->uPartitionStart)
     2225                    return vmdkError(pImage, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("VMDK: cannot go backwards for partition data in '%s'"), pszFilename);
     2226                else if (uStart != pPart->uPartitionStart)
    21332227                    cExtents++;
    2134 
    2135                 rc = vmdkCreateExtents(pImage, cExtents);
    2136                 if (VBOX_FAILURE(rc))
    2137                 {
    2138                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
    2139                     goto out;
    2140                 }
    2141 
    2142                 rc = RTFileOpen(&pImage->File, pszFilename,
    2143                                 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
    2144                 if (VBOX_FAILURE(rc))
    2145                 {
    2146                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
    2147                     goto out;
    2148                 }
    2149 
    2150                 /* Create base filename for the partition table extent. */
    2151                 /** @todo remove fixed buffer. */
    2152                 char pszPartition[1024];
    2153                 const char *pszBase = RTPathFilename(pszFilename);
    2154                 const char *pszExt = RTPathExt(pszBase);
    2155                 if (pszExt == NULL)
    2156                 {
    2157                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pszFilename);
    2158                     goto out;
    2159                 }
    2160                 memcpy(pszPartition, pszBase, pszExt - pszBase);
    2161                 memcpy(pszPartition + (pszExt - pszBase), "-pt", 3);
    2162                 memcpy(pszPartition + (pszExt - pszBase) + 3, pszExt, strlen(pszExt) + 1);
    2163 
    2164                 /* Second pass over the partitions, now define all extents. */
    2165                 uint64_t uPartOffset = 0;
    2166                 cExtents = 0;
    2167                 uStart = 0;
    2168                 for (unsigned i = 0; i < pRaw->cPartitions; i++)
    2169                 {
    2170                     PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
    2171                     if (pPart->cbPartitionData)
    2172                     {
    2173                         if (uStart != pPart->uPartitionDataStart)
    2174                         {
    2175                             pExtent = &pImage->pExtents[cExtents++];
    2176                             pExtent->pszBasename = NULL;
    2177                             pExtent->pszFullname = NULL;
    2178                             pExtent->enmType = VMDKETYPE_ZERO;
    2179                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionDataStart - uStart);
    2180                             pExtent->uSectorOffset = 0;
    2181                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2182                             pExtent->fMetaDirty = false;
    2183                         }
    2184                         uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
    2185                         pExtent = &pImage->pExtents[cExtents++];
    2186                         /* Set up basename for extent description. Cannot use StrDup. */
    2187                         size_t cbBasename = strlen(pszPartition) + 1;
    2188                         char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2189                         if (!pszBasename)
    2190                         {
    2191                             rc = VERR_NO_MEMORY;
    2192                             goto out;
    2193                         }
    2194                         memcpy(pszBasename, pszPartition, cbBasename);
    2195                         pExtent->pszBasename = pszBasename;
    2196 
    2197                         /* Set up full name for partition extent. */
    2198                         size_t cbDirname;
    2199                         char *pszDirname = RTStrDup(pImage->pszFilename);
    2200                         if (!pszDirname)
    2201                         {
    2202                             rc = VERR_NO_MEMORY;
    2203                             goto out;
    2204                         }
    2205                         RTPathStripFilename(pszDirname);
    2206                         cbDirname = strlen(pszDirname);
    2207                         char *pszFullname;
    2208                         rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname,
    2209                                           RTPATH_SLASH, pExtent->pszBasename);
    2210                         RTStrFree(pszDirname);
    2211                         if (VBOX_FAILURE(rc))
    2212                             goto out;
    2213                         pExtent->pszFullname = pszFullname;
    2214                         pExtent->enmType = VMDKETYPE_FLAT;
    2215                         pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartitionData);
    2216                         pExtent->uSectorOffset = uPartOffset;
    2217                         pExtent->enmAccess = VMDKACCESS_READWRITE;
    2218                         pExtent->fMetaDirty = false;
    2219 
    2220                         rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2221                                         RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    2222                         if (VBOX_FAILURE(rc))
    2223                         {
    2224                             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
    2225                             goto out;
    2226                         }
    2227                         rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uPartOffset), pPart->pvPartitionData, pPart->cbPartitionData, NULL);
    2228                         if (VBOX_FAILURE(rc))
    2229                         {
    2230                             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
    2231                             goto out;
    2232                         }
    2233                         uPartOffset += VMDK_BYTE2SECTOR(pPart->cbPartitionData);
    2234                     }
    2235                     if (pPart->cbPartition)
    2236                     {
    2237                         if (uStart != pPart->uPartitionStart)
    2238                         {
    2239                             pExtent = &pImage->pExtents[cExtents++];
    2240                             pExtent->pszBasename = NULL;
    2241                             pExtent->pszFullname = NULL;
    2242                             pExtent->enmType = VMDKETYPE_ZERO;
    2243                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionStart - uStart);
    2244                             pExtent->uSectorOffset = 0;
    2245                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2246                             pExtent->fMetaDirty = false;
    2247                         }
    2248                         uStart = pPart->uPartitionStart + pPart->cbPartition;
    2249                         pExtent = &pImage->pExtents[cExtents++];
    2250                         if (pPart->pszRawDevice)
    2251                         {
    2252                             /* Set up basename for extent description. Cannot use StrDup. */
    2253                             size_t cbBasename = strlen(pPart->pszRawDevice) + 1;
    2254                             char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
    2255                             if (!pszBasename)
    2256                             {
    2257                                 rc = VERR_NO_MEMORY;
    2258                                 goto out;
    2259                             }
    2260                             memcpy(pszBasename, pPart->pszRawDevice, cbBasename);
    2261                             pExtent->pszBasename = pszBasename;
    2262                             /* For raw disks the full name is identical to the base name. */
    2263                             pExtent->pszFullname = RTStrDup(pszBasename);
    2264                             if (!pExtent->pszFullname)
    2265                             {
    2266                                 rc = VERR_NO_MEMORY;
    2267                                 goto out;
    2268                             }
    2269                             pExtent->enmType = VMDKETYPE_FLAT;
    2270                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
    2271                             pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uPartitionStartOffset);
    2272                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2273                             pExtent->fMetaDirty = false;
    2274 
    2275                             rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
    2276                                             RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    2277                             if (VBOX_FAILURE(rc))
    2278                             {
    2279                                 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
    2280                                 goto out;
    2281                             }
    2282                         }
    2283                         else
    2284                         {
    2285                             pExtent->pszBasename = NULL;
    2286                             pExtent->pszFullname = NULL;
    2287                             pExtent->enmType = VMDKETYPE_ZERO;
    2288                             pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
    2289                             pExtent->uSectorOffset = 0;
    2290                             pExtent->enmAccess = VMDKACCESS_READWRITE;
    2291                             pExtent->fMetaDirty = false;
    2292                         }
    2293                     }
    2294                 }
    2295                 /* Another extent for filling up the rest of the image. */
    2296                 if (uStart != cbSize)
     2228                uStart = pPart->uPartitionStart + pPart->cbPartition;
     2229                cExtents++;
     2230            }
     2231        }
     2232        /* Another extent for filling up the rest of the image. */
     2233        if (uStart != cbSize)
     2234            cExtents++;
     2235
     2236        rc = vmdkCreateExtents(pImage, cExtents);
     2237        if (VBOX_FAILURE(rc))
     2238            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
     2239
     2240        rc = RTFileOpen(&pImage->File, pszFilename,
     2241                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
     2242        if (VBOX_FAILURE(rc))
     2243            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
     2244
     2245        /* Create base filename for the partition table extent. */
     2246        /** @todo remove fixed buffer without creating memory leaks. */
     2247        char pszPartition[1024];
     2248        const char *pszBase = RTPathFilename(pszFilename);
     2249        const char *pszExt = RTPathExt(pszBase);
     2250        if (pszExt == NULL)
     2251            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: invalid filename '%s'"), pszFilename);
     2252        char *pszBaseBase = RTStrDup(pszBase);
     2253        if (!pszBaseBase)
     2254            return VERR_NO_MEMORY;
     2255        RTPathStripExt(pszBaseBase);
     2256        RTStrPrintf(pszPartition, sizeof(pszPartition), "%s-pt%s",
     2257                    pszBaseBase, pszExt);
     2258        RTStrFree(pszBaseBase);
     2259
     2260        /* Second pass over the partitions, now define all extents. */
     2261        uint64_t uPartOffset = 0;
     2262        cExtents = 0;
     2263        uStart = 0;
     2264        for (unsigned i = 0; i < pRaw->cPartitions; i++)
     2265        {
     2266            PVBOXHDDRAWPART pPart = &pRaw->pPartitions[i];
     2267            if (pPart->cbPartitionData)
     2268            {
     2269                if (uStart != pPart->uPartitionDataStart)
    22972270                {
    22982271                    pExtent = &pImage->pExtents[cExtents++];
     
    23002273                    pExtent->pszFullname = NULL;
    23012274                    pExtent->enmType = VMDKETYPE_ZERO;
    2302                     pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize - uStart);
     2275                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionDataStart - uStart);
    23032276                    pExtent->uSectorOffset = 0;
    23042277                    pExtent->enmAccess = VMDKACCESS_READWRITE;
    23052278                    pExtent->fMetaDirty = false;
    23062279                }
    2307 
    2308                 pImage->enmImageType = enmType;
    2309                 rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "partitionedDevice");
     2280                uStart = pPart->uPartitionDataStart + pPart->cbPartitionData;
     2281                pExtent = &pImage->pExtents[cExtents++];
     2282                /* Set up basename for extent description. Can't use StrDup. */
     2283                size_t cbBasename = strlen(pszPartition) + 1;
     2284                char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
     2285                if (!pszBasename)
     2286                    return VERR_NO_MEMORY;
     2287                memcpy(pszBasename, pszPartition, cbBasename);
     2288                pExtent->pszBasename = pszBasename;
     2289
     2290                /* Set up full name for partition extent. */
     2291                size_t cbDirname;
     2292                char *pszDirname = RTStrDup(pImage->pszFilename);
     2293                if (!pszDirname)
     2294                    return VERR_NO_MEMORY;
     2295                RTPathStripFilename(pszDirname);
     2296                cbDirname = strlen(pszDirname);
     2297                char *pszFullname;
     2298                rc = RTStrAPrintf(&pszFullname, "%s%c%s", pszDirname,
     2299                                  RTPATH_SLASH, pExtent->pszBasename);
     2300                RTStrFree(pszDirname);
    23102301                if (VBOX_FAILURE(rc))
     2302                    return rc;
     2303                pExtent->pszFullname = pszFullname;
     2304                pExtent->enmType = VMDKETYPE_FLAT;
     2305                pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartitionData);
     2306                pExtent->uSectorOffset = uPartOffset;
     2307                pExtent->enmAccess = VMDKACCESS_READWRITE;
     2308                pExtent->fMetaDirty = false;
     2309
     2310                rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2311                                RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
     2312                if (VBOX_FAILURE(rc))
     2313                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
     2314                rc = RTFileWriteAt(pExtent->File,
     2315                                   VMDK_SECTOR2BYTE(uPartOffset),
     2316                                   pPart->pvPartitionData,
     2317                                   pPart->cbPartitionData, NULL);
     2318                if (VBOX_FAILURE(rc))
     2319                    return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
     2320                uPartOffset += VMDK_BYTE2SECTOR(pPart->cbPartitionData);
     2321            }
     2322            if (pPart->cbPartition)
     2323            {
     2324                if (uStart != pPart->uPartitionStart)
    23112325                {
    2312                     rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
    2313                     goto out;
     2326                    pExtent = &pImage->pExtents[cExtents++];
     2327                    pExtent->pszBasename = NULL;
     2328                    pExtent->pszFullname = NULL;
     2329                    pExtent->enmType = VMDKETYPE_ZERO;
     2330                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->uPartitionStart - uStart);
     2331                    pExtent->uSectorOffset = 0;
     2332                    pExtent->enmAccess = VMDKACCESS_READWRITE;
     2333                    pExtent->fMetaDirty = false;
     2334                }
     2335                uStart = pPart->uPartitionStart + pPart->cbPartition;
     2336                pExtent = &pImage->pExtents[cExtents++];
     2337                if (pPart->pszRawDevice)
     2338                {
     2339                    /* Set up basename for extent descr. Can't use StrDup. */
     2340                    size_t cbBasename = strlen(pPart->pszRawDevice) + 1;
     2341                    char *pszBasename = (char *)RTMemTmpAlloc(cbBasename);
     2342                    if (!pszBasename)
     2343                        return VERR_NO_MEMORY;
     2344                    memcpy(pszBasename, pPart->pszRawDevice, cbBasename);
     2345                    pExtent->pszBasename = pszBasename;
     2346                    /* For raw disks full name is identical to base name. */
     2347                    pExtent->pszFullname = RTStrDup(pszBasename);
     2348                    if (!pExtent->pszFullname)
     2349                        return VERR_NO_MEMORY;
     2350                    pExtent->enmType = VMDKETYPE_FLAT;
     2351                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
     2352                    pExtent->uSectorOffset = VMDK_BYTE2SECTOR(pPart->uPartitionStartOffset);
     2353                    pExtent->enmAccess = VMDKACCESS_READWRITE;
     2354                    pExtent->fMetaDirty = false;
     2355
     2356                    rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2357                                    RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     2358                    if (VBOX_FAILURE(rc))
     2359                        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
     2360                }
     2361                else
     2362                {
     2363                    pExtent->pszBasename = NULL;
     2364                    pExtent->pszFullname = NULL;
     2365                    pExtent->enmType = VMDKETYPE_ZERO;
     2366                    pExtent->cNominalSectors = VMDK_BYTE2SECTOR(pPart->cbPartition);
     2367                    pExtent->uSectorOffset = 0;
     2368                    pExtent->enmAccess = VMDKACCESS_READWRITE;
     2369                    pExtent->fMetaDirty = false;
    23142370                }
    23152371            }
    23162372        }
    2317         else
    2318         {
    2319             rc = VERR_NOT_IMPLEMENTED;
    2320             goto out;
    2321         }
    2322     }
    2323     else
    2324     {
    2325         /* Normal (growing) image which is not split into pieces. */
    2326         rc = vmdkCreateExtents(pImage, 1);
    2327         if (VBOX_FAILURE(rc))
    2328         {
    2329             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
    2330             goto out;
    2331         }
    2332         pExtent = &pImage->pExtents[0];
    2333         pImage->File = NIL_RTFILE;
    2334         rc = RTFileOpen(&pExtent->File, pszFilename,
     2373        /* Another extent for filling up the rest of the image. */
     2374        if (uStart != cbSize)
     2375        {
     2376            pExtent = &pImage->pExtents[cExtents++];
     2377            pExtent->pszBasename = NULL;
     2378            pExtent->pszFullname = NULL;
     2379            pExtent->enmType = VMDKETYPE_ZERO;
     2380            pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize - uStart);
     2381            pExtent->uSectorOffset = 0;
     2382            pExtent->enmAccess = VMDKACCESS_READWRITE;
     2383            pExtent->fMetaDirty = false;
     2384        }
     2385    }
     2386
     2387    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
     2388                            pRaw->fRawDisk ?
     2389                            "fullDevice" : "partitionedDevice");
     2390    if (VBOX_FAILURE(rc))
     2391        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
     2392    return rc;
     2393}
     2394
     2395static int vmdkCreateRegularImage(PVMDKIMAGE pImage, const char *pszFilename,
     2396                                  VDIMAGETYPE enmType, uint64_t cbSize,
     2397                                  unsigned uImageFlags,
     2398                                  PFNVMPROGRESS pfnProgress, void *pvUser,
     2399                                  unsigned uPercentStart,
     2400                                  unsigned uPercentSpan)
     2401{
     2402    int rc = VINF_SUCCESS;
     2403    unsigned cExtents = 1;
     2404    uint64_t cbOffset = 0;
     2405    uint64_t cbRemaining = cbSize;
     2406
     2407    if (uImageFlags & VD_VMDK_IMAGE_FLAGS_SPLIT_2G)
     2408    {
     2409        cExtents = cbSize / VMDK_2G_SPLIT_SIZE;
     2410        /* Do proper extent computation: need one smaller extent if the total
     2411         * size isn't evenly divisible by the split size. */
     2412        if (cbSize % VMDK_2G_SPLIT_SIZE)
     2413            cExtents++;
     2414    }
     2415    rc = vmdkCreateExtents(pImage, cExtents);
     2416    if (VBOX_FAILURE(rc))
     2417        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new extent list in '%s'"), pszFilename);
     2418
     2419    /* Basename strings needed for constructing the extent names. */
     2420    char *pszBasenameSubstr = RTPathFilename(pszFilename);
     2421    Assert(pszBasenameSubstr);
     2422    size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
     2423
     2424    /* Create searate descriptor file if necessary. */
     2425    if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED)
     2426    {
     2427        rc = RTFileOpen(&pImage->File, pszFilename,
    23352428                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
    23362429        if (VBOX_FAILURE(rc))
    2337         {
    2338             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pszFilename);
    2339             goto out;
    2340         }
    2341 
    2342         /* Set up basename for extent description. Cannot use StrDup, as it is
    2343          * not guaranteed that the memory can be freed with RTMemTmpFree, which
    2344          * must be used as in other code paths StrDup is not usable. */
    2345         char *pszBasenameSubstr = RTPathFilename(pszFilename);
    2346         Assert(pszBasenameSubstr);
    2347         size_t cbBasenameSubstr = strlen(pszBasenameSubstr) + 1;
    2348         char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
    2349         if (!pszBasename)
    2350         {
    2351             rc = VERR_NO_MEMORY;
    2352             goto out;
    2353         }
    2354         memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
    2355         pExtent->pszBasename = pszBasename;
    2356         pExtent->pszFullname = RTStrDup(pszFilename);
    2357         if (!pExtent->pszFullname)
    2358         {
    2359             rc = VERR_NO_MEMORY;
    2360             goto out;
    2361         }
    2362         pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
    2363         pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbSize, 65536));
    2364         pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536);
    2365         pExtent->uDescriptorSector = 1;
    2366         pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
    2367         pExtent->cGTEntries = 512;
    2368         cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
    2369         pExtent->cSectorsPerGDE = cSectorsPerGDE;
    2370         pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
    2371         cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     2430            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pszFilename);
     2431        pImage->pszFilename = RTStrDup(pszFilename);
     2432    }
     2433    else
     2434        pImage->File = NIL_RTFILE;
     2435
     2436    /* Set up all extents. */
     2437    for (unsigned i = 0; i < cExtents; i++)
     2438    {
     2439        PVMDKEXTENT pExtent = &pImage->pExtents[i];
     2440        uint64_t cbExtent = cbRemaining;
     2441
     2442        /* Set up fullname/basename for extent description. Cannot use StrDup
     2443         * for basename, as it is not guaranteed that the memory can be freed
     2444         * with RTMemTmpFree, which must be used as in other code paths
     2445         * StrDup is not usable. */
     2446        if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED)
     2447        {
     2448            char *pszBasename = (char *)RTMemTmpAlloc(cbBasenameSubstr);
     2449            if (!pszBasename)
     2450                return VERR_NO_MEMORY;
     2451            memcpy(pszBasename, pszBasenameSubstr, cbBasenameSubstr);
     2452            pExtent->pszBasename = pszBasename;
     2453        }
     2454        else
     2455        {
     2456            char *pszBasenameExt = RTPathExt(pszBasenameSubstr);
     2457            char *pszBasenameBase = RTStrDup(pszBasenameSubstr);
     2458            RTPathStripExt(pszBasenameBase);
     2459            char *pszTmp;
     2460            size_t cbTmp;
     2461            if (enmType == VD_IMAGE_TYPE_FIXED)
     2462            {
     2463                if (cExtents == 1)
     2464                    rc = RTStrAPrintf(&pszTmp, "%s-flat%s", pszBasenameBase,
     2465                                      pszBasenameExt);
     2466                else
     2467                    rc = RTStrAPrintf(&pszTmp, "%s-f%03d%s", pszBasenameBase,
     2468                                      i+1, pszBasenameExt);
     2469            }
     2470            else
     2471                rc = RTStrAPrintf(&pszTmp, "%s-s%03d%s", pszBasenameBase, i+1,
     2472                                  pszBasenameExt);
     2473            RTStrFree(pszBasenameBase);
     2474            if (VBOX_FAILURE(rc))
     2475                return rc;
     2476            cbTmp = strlen(pszTmp) + 1;
     2477            char *pszBasename = (char *)RTMemTmpAlloc(cbTmp);
     2478            if (!pszBasename)
     2479                return VERR_NO_MEMORY;
     2480            memcpy(pszBasename, pszTmp, cbTmp);
     2481            RTStrFree(pszTmp);
     2482            pExtent->pszBasename = pszBasename;
     2483            cbExtent = RT_MIN(cbRemaining, VMDK_2G_SPLIT_SIZE);
     2484        }
     2485        char *pszBasedirectory = RTStrDup(pszFilename);
     2486        RTPathStripFilename(pszBasedirectory);
     2487        char *pszFN;
     2488        rc = RTStrAPrintf(&pszFN, "%s%c%s", pszBasedirectory, RTPATH_SLASH,
     2489                          pExtent->pszBasename);
     2490        RTStrFree(pszBasedirectory);
     2491        if (VBOX_FAILURE(rc))
     2492            return rc;
     2493        pExtent->pszFullname = pszFN;
     2494
     2495        /* Create file for extent. */
     2496        rc = RTFileOpen(&pExtent->File, pExtent->pszFullname,
     2497                        RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
     2498        if (VBOX_FAILURE(rc))
     2499            return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
     2500        if (enmType == VD_IMAGE_TYPE_FIXED)
     2501        {
     2502            rc = RTFileSetSize(pExtent->File, cbExtent);
     2503            if (VBOX_FAILURE(rc))
     2504                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
     2505        }
     2506
     2507        /* Place descriptor file information (where integrated). */
     2508        if (cExtents == 1 && enmType != VD_IMAGE_TYPE_FIXED)
     2509        {
     2510            pExtent->uDescriptorSector = 1;
     2511            pExtent->cDescriptorSectors = VMDK_BYTE2SECTOR(pImage->cbDescAlloc);
     2512            /* The descriptor is part of the (only) extent. */
     2513            pExtent->pDescData = pImage->pDescData;
     2514            pImage->pDescData = NULL;
     2515        }
     2516
     2517        if (enmType == VD_IMAGE_TYPE_NORMAL)
     2518        {
     2519            uint64_t cSectorsPerGDE, cSectorsPerGD;
     2520            pExtent->enmType = VMDKETYPE_HOSTED_SPARSE;
     2521            pExtent->cSectors = VMDK_BYTE2SECTOR(RT_ALIGN_64(cbExtent, 65536));
     2522            pExtent->cSectorsPerGrain = VMDK_BYTE2SECTOR(65536);
     2523            pExtent->cGTEntries = 512;
     2524            cSectorsPerGDE = pExtent->cGTEntries * pExtent->cSectorsPerGrain;
     2525            pExtent->cSectorsPerGDE = cSectorsPerGDE;
     2526            pExtent->cGDEntries = (pExtent->cSectors + cSectorsPerGDE - 1) / cSectorsPerGDE;
     2527            cSectorsPerGD = (pExtent->cGDEntries + (512 / sizeof(uint32_t) - 1)) / (512 / sizeof(uint32_t));
     2528        }
     2529        else
     2530            pExtent->enmType = VMDKETYPE_FLAT;
     2531
    23722532        pExtent->enmAccess = VMDKACCESS_READWRITE;
    23732533        pExtent->fUncleanShutdown = true;
    2374         pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbSize);
    2375         pExtent->uSectorOffset = 0;
     2534        pExtent->cNominalSectors = VMDK_BYTE2SECTOR(cbExtent);
     2535        pExtent->uSectorOffset = VMDK_BYTE2SECTOR(cbOffset);
    23762536        pExtent->fMetaDirty = true;
    23772537
    2378         rc = vmdkCreateGrainDirectory(pExtent, pExtent->uDescriptorSector + pExtent->cDescriptorSectors, true);
    2379         if (VBOX_FAILURE(rc))
    2380         {
    2381             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pszFilename);
    2382             goto out;
    2383         }
    2384 
    2385         pImage->enmImageType = enmType;
    2386         rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType", "monolithicSparse");
    2387         if (VBOX_FAILURE(rc))
    2388         {
    2389             rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
    2390             goto out;
    2391         }
    2392 
    2393         /* The descriptor is part of the extent, move info to extent. */
    2394         pExtent->pDescData = pImage->pDescData;
    2395         pImage->pDescData = NULL;
    2396     }
    2397 
     2538        if (enmType == VD_IMAGE_TYPE_NORMAL)
     2539        {
     2540            rc = vmdkCreateGrainDirectory(pExtent,
     2541                                            pExtent->uDescriptorSector
     2542                                          + pExtent->cDescriptorSectors,
     2543                                          true);
     2544            if (VBOX_FAILURE(rc))
     2545                return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new grain directory in '%s'"), pExtent->pszFullname);
     2546        }
     2547
     2548        if (VBOX_SUCCESS(rc) && pfnProgress)
     2549            pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2550                        i * uPercentSpan / cExtents + uPercentStart,
     2551                        pvUser);
     2552
     2553        cbRemaining -= cbExtent;
     2554        cbOffset += cbExtent;
     2555    }
     2556
     2557    const char *pszDescType = NULL;
     2558    if (enmType == VD_IMAGE_TYPE_FIXED)
     2559    {
     2560        pszDescType =   (cExtents == 1)
     2561                      ? "monolithicFlat" : "twoGbMaxExtentFlat";
     2562    }
     2563    else if (enmType == VD_IMAGE_TYPE_NORMAL)
     2564    {
     2565        pszDescType =   (cExtents == 1)
     2566                      ? "monolithicSparse" : "twoGbMaxExtentSparse";
     2567    }
     2568    else
     2569        AssertMsgFailed(("invalid image type %d\n", enmType));
     2570    rc = vmdkDescBaseSetStr(pImage, &pImage->Descriptor, "createType",
     2571                            pszDescType);
     2572    if (VBOX_FAILURE(rc))
     2573        return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set the image type in '%s'"), pszFilename);
     2574    return rc;
     2575}
     2576
     2577static int vmdkCreateImage(PVMDKIMAGE pImage, const char *pszFilename,
     2578                           VDIMAGETYPE enmType, uint64_t cbSize,
     2579                           unsigned uImageFlags, const char *pszComment,
     2580                           PCPDMMEDIAGEOMETRY pPCHSGeometry,
     2581                           PCPDMMEDIAGEOMETRY pLCHSGeometry,
     2582                           PFNVMPROGRESS pfnProgress, void *pvUser,
     2583                           unsigned uPercentStart, unsigned uPercentSpan)
     2584{
     2585    int rc;
     2586
     2587    pImage->uImageFlags = uImageFlags;
     2588    rc = vmdkCreateDescriptor(pImage, pImage->pDescData, pImage->cbDescAlloc,
     2589                              &pImage->Descriptor);
     2590    if (VBOX_FAILURE(rc))
     2591    {
     2592        rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new descriptor in '%s'"), pszFilename);
     2593        goto out;
     2594    }
     2595
     2596    if (    enmType == VD_IMAGE_TYPE_FIXED
     2597        &&  (uImageFlags & VD_VMDK_IMAGE_FLAGS_RAWDISK))
     2598    {
     2599        /* Raw disk image (includes raw partition). */
     2600        const PVBOXHDDRAW pRaw = (const PVBOXHDDRAW)pszComment;
     2601        /* As the comment is misused, zap it so that no garbage comment
     2602         * is set below. */
     2603        pszComment = NULL;
     2604        rc = vmdkCreateRawImage(pImage, pszFilename, pRaw, cbSize);
     2605    }
     2606    else if (   enmType == VD_IMAGE_TYPE_FIXED
     2607             || enmType == VD_IMAGE_TYPE_NORMAL)
     2608    {
     2609        /* Regular fixed or sparse image (monolithic or split). */
     2610        rc = vmdkCreateRegularImage(pImage, pszFilename, enmType, cbSize,
     2611                                    uImageFlags, pfnProgress, pvUser,
     2612                                    uPercentStart, uPercentSpan * 95 / 100);
     2613    }
     2614    else
     2615    {
     2616        /* Unknown/invalid image type. */
     2617        rc = VERR_NOT_IMPLEMENTED;
     2618    }
     2619
     2620    if (VBOX_FAILURE(rc))
     2621        goto out;
     2622
     2623    if (VBOX_SUCCESS(rc) && pfnProgress)
     2624        pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2625                    uPercentStart + uPercentSpan * 98 / 100, pvUser);
     2626
     2627    pImage->enmImageType = enmType;
    23982628    pImage->cbSize = cbSize;
    2399     if (pImage->cCylinders >= 1024 || pImage->cHeads != 16)
    2400         pImage->enmTranslation = PDMBIOSTRANSLATION_LBA;
    2401     else
    2402         pImage->enmTranslation = PDMBIOSTRANSLATION_NONE;
    24032629
    24042630    for (unsigned i = 0; i < pImage->cExtents; i++)
    24052631    {
    2406         pExtent = &pImage->pExtents[i];
     2632        PVMDKEXTENT pExtent = &pImage->pExtents[i];
    24072633
    24082634        rc = vmdkDescExtInsert(pImage, &pImage->Descriptor, pExtent->enmAccess,
     
    24172643    vmdkDescExtRemoveDummy(pImage, &pImage->Descriptor);
    24182644
    2419     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    2420                            "ddb.geometry.cylinders", cCylinders);
    2421     if (VBOX_FAILURE(rc))
    2422         goto out;
    2423     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    2424                            "ddb.geometry.heads", cHeads);
    2425     if (VBOX_FAILURE(rc))
    2426         goto out;
    2427     rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    2428                            "ddb.geometry.sectors", cSectors);
    2429     if (VBOX_FAILURE(rc))
    2430         goto out;
    2431 
    2432     pImage->cCylinders = cCylinders;
    2433     pImage->cHeads = cHeads;
    2434     pImage->cSectors = cSectors;
     2645    if (    pPCHSGeometry->cCylinders == 0
     2646        ||  pPCHSGeometry->cHeads == 0
     2647        ||  pPCHSGeometry->cSectors == 0)
     2648    {
     2649        rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
     2650        if (VBOX_FAILURE(rc))
     2651            goto out;
     2652    }
     2653    if (    pLCHSGeometry->cCylinders == 0
     2654        ||  pLCHSGeometry->cHeads == 0
     2655        ||  pLCHSGeometry->cSectors == 0)
     2656    {
     2657        rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
     2658        if (VBOX_FAILURE(rc))
     2659            goto out;
     2660    }
     2661
     2662    pImage->LCHSGeometry = *pLCHSGeometry;
     2663    pImage->PCHSGeometry = *pPCHSGeometry;
    24352664
    24362665    rc = RTUuidCreate(&pImage->ImageUuid);
     
    24542683    RTUuidClear(&pImage->ModificationUuid);
    24552684    rc = vmdkDescDDBSetUuid(pImage, &pImage->Descriptor,
    2456                             "ddb.uuid.modification", &pImage->ModificationUuid);
     2685                            "ddb.uuid.modification",
     2686                            &pImage->ModificationUuid);
    24572687    if (VBOX_FAILURE(rc))
    24582688    {
     
    24722702    }
    24732703
     2704    if (VBOX_SUCCESS(rc) && pfnProgress)
     2705        pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2706                    uPercentStart + uPercentSpan * 99 / 100, pvUser);
     2707
    24742708    rc = vmdkFlushImage(pImage);
    24752709
    24762710out:
     2711    if (VBOX_SUCCESS(rc) && pfnProgress)
     2712        pfnProgress(NULL /* WARNING! pVM=NULL  */,
     2713                    uPercentStart + uPercentSpan, pvUser);
     2714
    24772715    if (VBOX_FAILURE(rc))
    24782716        vmdkFreeImage(pImage, rc != VERR_ALREADY_EXISTS);
     
    25872825            case VMDKETYPE_FLAT:
    25882826                /** @todo implement proper path absolute check. */
    2589                 if (pExtent->File != NIL_RTFILE && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) && !(pExtent->pszBasename[0] == RTPATH_SLASH))
     2827                if (   pExtent->File != NIL_RTFILE
     2828                    && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     2829                    && !(pExtent->pszBasename[0] == RTPATH_SLASH))
    25902830                    rc = RTFileFlush(pExtent->File);
    25912831                break;
     
    26032843}
    26042844
    2605 static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector, PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
     2845static int vmdkFindExtent(PVMDKIMAGE pImage, uint64_t offSector,
     2846                          PVMDKEXTENT *ppExtent, uint64_t *puSectorInExtent)
    26062847{
    26072848    PVMDKEXTENT pExtent = NULL;
     
    26272868}
    26282869
    2629 static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector, unsigned uExtent)
     2870static uint32_t vmdkGTCacheHash(PVMDKGTCACHE pCache, uint64_t uSector,
     2871                                unsigned uExtent)
    26302872{
    26312873    /** @todo this hash function is quite simple, maybe use a better one which
     
    26882930 */
    26892931static int vmdkAllocGrain(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
    2690                           uint64_t uSector, const void *pvBuf, uint64_t cbWrite)
     2932                          uint64_t uSector, const void *pvBuf,
     2933                          uint64_t cbWrite)
    26912934{
    26922935    uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
     
    27222965         * should be acceptable. */
    27232966        memset(aGTDataTmp, '\0', sizeof(aGTDataTmp));
    2724         for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++)
    2725         {
    2726             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
     2967        for (unsigned i = 0;
     2968             i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
     2969             i++)
     2970        {
     2971            rc = RTFileWriteAt(pExtent->File,
     2972                               VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
     2973                               aGTDataTmp, sizeof(aGTDataTmp), NULL);
    27272974            if (VBOX_FAILURE(rc))
    27282975                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
     
    27392986             * bit slower. But as this is a pretty infrequently occurring case
    27402987             * it should be acceptable. */
    2741             for (unsigned i = 0; i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE; i++)
     2988            for (unsigned i = 0;
     2989                 i < pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE;
     2990                 i++)
    27422991            {
    2743                 rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp), aGTDataTmp, sizeof(aGTDataTmp), NULL);
     2992                rc = RTFileWriteAt(pExtent->File,
     2993                                   VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
     2994                                   aGTDataTmp, sizeof(aGTDataTmp), NULL);
    27442995                if (VBOX_FAILURE(rc))
    27452996                    return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
     
    27523003         * some unused sectors in the extent. */
    27533004        uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
    2754         rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), &uGTSectorLE, sizeof(uGTSectorLE), NULL);
     3005        rc = RTFileWriteAt(pExtent->File,
     3006                           VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
     3007                           &uGTSectorLE, sizeof(uGTSectorLE), NULL);
    27553008        if (VBOX_FAILURE(rc))
    27563009            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
     
    27583011        {
    27593012            uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
    2760             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE), &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
     3013            rc = RTFileWriteAt(pExtent->File,
     3014                               VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
     3015                               &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
    27613016            if (VBOX_FAILURE(rc))
    27623017                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
     
    28323087}
    28333088
    2834 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData)
     3089
     3090static int vmdkCheckIfValid(const char *pszFilename)
     3091{
     3092    int rc = VINF_SUCCESS;
     3093    PVMDKIMAGE pImage = (PVMDKIMAGE)RTMemAllocZ(sizeof(VMDKIMAGE));
     3094    if (!pImage)
     3095    {
     3096        rc = VERR_NO_MEMORY;
     3097        goto out;
     3098    }
     3099    pImage->pszFilename = pszFilename;
     3100    pImage->File = NIL_RTFILE;
     3101    pImage->pExtents = NULL;
     3102    pImage->pGTCache = NULL;
     3103    pImage->pDescData = NULL;
     3104    pImage->pfnError = NULL;
     3105    pImage->pvErrorUser = NULL;
     3106    /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
     3107     * much as possible in vmdkOpenImage. */
     3108    rc = vmdkOpenImage(pImage, pszFilename,
     3109                       VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY);
     3110    vmdkFreeImage(pImage, false);
     3111
     3112out:
     3113    return rc;
     3114}
     3115
     3116static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
     3117                    PFNVDERROR pfnError, void *pvErrorUser,
     3118                    void **ppvBackendData)
    28353119{
    28363120    int rc;
     
    28713155static int vmdkCreate(const char *pszFilename, VDIMAGETYPE enmType,
    28723156                      uint64_t cbSize, unsigned uImageFlags,
    2873                       const char *pszComment, uint32_t cCylinders,
    2874                       uint32_t cHeads, uint32_t cSectors, unsigned uOpenFlags,
    2875                       PFNVMPROGRESS pfnProgress, void *pvUser,
    2876                       PFNVDERROR pfnError, void *pvErrorUser,
    2877                       void **ppvBackendData)
     3157                      const char *pszComment,
     3158                      PCPDMMEDIAGEOMETRY pPCHSGeometry,
     3159                      PCPDMMEDIAGEOMETRY pLCHSGeometry,
     3160                      unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
     3161                      void *pvUser, unsigned uPercentStart,
     3162                      unsigned uPercentSpan, PFNVDERROR pfnError,
     3163                      void *pvErrorUser, void **ppvBackendData)
    28783164{
    28793165    int rc;
     
    29113197
    29123198    rc = vmdkCreateImage(pImage, pszFilename, enmType, cbSize, uImageFlags,
    2913                          pszComment, cCylinders, cHeads, cSectors);
     3199                         pszComment, pPCHSGeometry, pLCHSGeometry,
     3200                         pfnProgress, pvUser, uPercentStart, uPercentSpan);
    29143201    if (VBOX_SUCCESS(rc))
    29153202    {
     
    29273214
    29283215out:
    2929     /** @todo implement meaningful progress stuff (especially for fixed images). */
    2930     if (    VBOX_SUCCESS(rc)
    2931         &&  pfnProgress)
    2932         pfnProgress(NULL /* WARNING! pVM=NULL  */, 100, pvUser);
    2933 
    29343216    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
    29353217    return rc;
     3218}
     3219
     3220static int vmdkRename(void *pBackendData, const char *pszFilename)
     3221{
     3222    return VERR_NOT_IMPLEMENTED;
    29363223}
    29373224
     
    29503237}
    29513238
    2952 static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf, size_t cbRead, size_t *pcbActuallyRead)
     3239static int vmdkRead(void *pBackendData, uint64_t uOffset, void *pvBuf,
     3240                    size_t cbRead, size_t *pcbActuallyRead)
    29533241{
    29543242    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    30043292            break;
    30053293        case VMDKETYPE_FLAT:
    3006             rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel),
     3294            rc = RTFileReadAt(pExtent->File,
     3295                              VMDK_SECTOR2BYTE(uSectorExtentRel),
    30073296                              pvBuf, cbRead, NULL);
    30083297            break;
     
    30173306}
    30183307
    3019 static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf, size_t cbWrite, size_t *pcbWriteProcess, size_t *pcbPreRead, size_t *pcbPostRead)
     3308static int vmdkWrite(void *pBackendData, uint64_t uOffset, const void *pvBuf,
     3309                     size_t cbWrite, size_t *pcbWriteProcess,
     3310                     size_t *pcbPreRead, size_t *pcbPostRead)
    30203311{
    30213312    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    31003391            /* Clip write range to remain in this extent. */
    31013392            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
    3102             rc = RTFileWriteAt(pExtent->File, VMDK_SECTOR2BYTE(uSectorExtentRel), pvBuf, cbWrite, NULL);
     3393            rc = RTFileWriteAt(pExtent->File,
     3394                               VMDK_SECTOR2BYTE(uSectorExtentRel),
     3395                               pvBuf, cbWrite, NULL);
    31033396            break;
    31043397        case VMDKETYPE_ZERO:
     
    31233416}
    31243417
     3418static unsigned vmdkGetVersion(void *pBackendData)
     3419{
     3420    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3421
     3422    Assert(pImage);
     3423
     3424    if (pImage)
     3425        return VMDK_IMAGE_VERSION;
     3426    else
     3427        return 0;
     3428}
     3429
    31253430static int vmdkGetImageType(void *pBackendData, PVDIMAGETYPE penmImageType)
    31263431{
     
    31513456}
    31523457
    3153 static int vmdkGetGeometry(void *pBackendData, unsigned *pcCylinders, unsigned *pcHeads, unsigned *pcSectors)
     3458static uint64_t vmdkGetFileSize(void *pBackendData)
     3459{
     3460    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3461
     3462    Assert(pImage);
     3463
     3464    if (pImage)
     3465    {
     3466        int rc;
     3467        uint64_t cbFile, cb = 0;
     3468        if (pImage->File != NIL_RTFILE)
     3469        {
     3470            rc = RTFileGetSize(pImage->File, &cbFile);
     3471            if (VBOX_SUCCESS(rc))
     3472                cb += cbFile;
     3473            for (unsigned i = 0; i <= pImage->cExtents; i++)
     3474            {
     3475                rc = RTFileGetSize(pImage->File, &cbFile);
     3476                if (VBOX_SUCCESS(rc))
     3477                    cb += cbFile;
     3478            }
     3479        }
     3480        return cb;
     3481    }
     3482    else
     3483        return 0;
     3484}
     3485
     3486static int vmdkGetPCHSGeometry(void *pBackendData,
     3487                               PPDMMEDIAGEOMETRY pPCHSGeometry)
    31543488{
    31553489    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    31603494    if (pImage)
    31613495    {
    3162         if (pImage->cCylinders)
    3163         {
    3164             *pcCylinders = pImage->cCylinders;
    3165             *pcHeads = pImage->cHeads;
    3166             *pcSectors = pImage->cSectors;
     3496        if (pImage->PCHSGeometry.cCylinders)
     3497        {
     3498            *pPCHSGeometry = pImage->PCHSGeometry;
    31673499            rc = VINF_SUCCESS;
    31683500        }
     
    31733505        rc = VERR_VDI_NOT_OPENED;
    31743506    LogFlow(("%s: returned %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc,
    3175              pImage->cCylinders, pImage->cHeads, pImage->cSectors));
    3176     return rc;
    3177 }
    3178 
    3179 static int vmdkSetGeometry(void *pBackendData, unsigned cCylinders, unsigned cHeads, unsigned cSectors)
     3507             pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors));
     3508    return rc;
     3509}
     3510
     3511static int vmdkSetPCHSGeometry(void *pBackendData,
     3512                               PCPDMMEDIAGEOMETRY pPCHSGeometry)
    31803513{
    31813514    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    31913524            goto out;
    31923525        }
    3193         rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    3194                                "ddb.geometry.cylinders", cCylinders);
     3526        rc = vmdkDescSetPCHSGeometry(pImage, pPCHSGeometry);
    31953527        if (VBOX_FAILURE(rc))
    31963528            goto out;
    3197         rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    3198                                "ddb.geometry.heads", cHeads);
     3529
     3530        pImage->PCHSGeometry = *pPCHSGeometry;
     3531        rc = VINF_SUCCESS;
     3532    }
     3533    else
     3534        rc = VERR_VDI_NOT_OPENED;
     3535
     3536out:
     3537    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
     3538    return rc;
     3539}
     3540
     3541static int vmdkGetLCHSGeometry(void *pBackendData,
     3542                               PPDMMEDIAGEOMETRY pLCHSGeometry)
     3543{
     3544    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3545    int rc;
     3546
     3547    Assert(pImage);
     3548
     3549    if (pImage)
     3550    {
     3551        if (pImage->LCHSGeometry.cCylinders)
     3552        {
     3553            *pLCHSGeometry = pImage->LCHSGeometry;
     3554            rc = VINF_SUCCESS;
     3555        }
     3556        else
     3557            rc = VERR_VDI_GEOMETRY_NOT_SET;
     3558    }
     3559    else
     3560        rc = VERR_VDI_NOT_OPENED;
     3561    LogFlow(("%s: returned %Vrc (CHS=%u/%u/%u)\n", __FUNCTION__, rc,
     3562             pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors));
     3563    return rc;
     3564}
     3565
     3566static int vmdkSetLCHSGeometry(void *pBackendData,
     3567                               PCPDMMEDIAGEOMETRY pLCHSGeometry)
     3568{
     3569    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3570    int rc;
     3571
     3572    Assert(pImage);
     3573
     3574    if (pImage)
     3575    {
     3576        if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     3577        {
     3578            rc = VERR_VDI_IMAGE_READ_ONLY;
     3579            goto out;
     3580        }
     3581        rc = vmdkDescSetLCHSGeometry(pImage, pLCHSGeometry);
    31993582        if (VBOX_FAILURE(rc))
    32003583            goto out;
    3201         rc = vmdkDescDDBSetU32(pImage, &pImage->Descriptor,
    3202                                "ddb.geometry.sectors", cSectors);
    3203         if (VBOX_FAILURE(rc))
    3204             goto out;
    3205 
    3206         pImage->cCylinders = cCylinders;
    3207         pImage->cHeads = cHeads;
    3208         pImage->cSectors = cSectors;
     3584
     3585        pImage->LCHSGeometry = *pLCHSGeometry;
    32093586        rc = VINF_SUCCESS;
    32103587    }
     
    32173594}
    32183595
    3219 static int vmdkGetTranslation(void *pBackendData, PPDMBIOSTRANSLATION penmTranslation)
     3596static unsigned vmdkGetImageFlags(void *pBackendData)
    32203597{
    32213598    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3222     int rc;
     3599    unsigned uImageFlags;
    32233600
    32243601    Assert(pImage);
    32253602
    32263603    if (pImage)
    3227     {
    3228         if (pImage->enmTranslation)
    3229         {
    3230             *penmTranslation = pImage->enmTranslation;
    3231             rc = VINF_SUCCESS;
    3232         }
    3233         else
    3234             rc = VERR_VDI_GEOMETRY_NOT_SET;
    3235     }
     3604        uImageFlags = pImage->uImageFlags;
    32363605    else
    3237         rc = VERR_VDI_NOT_OPENED;
    3238     LogFlow(("%s: returned %Vrc (%d)\n", __FUNCTION__, rc,
    3239              pImage->enmTranslation));
    3240     return rc;
    3241 }
    3242 
    3243 static int vmdkSetTranslation(void *pBackendData, PDMBIOSTRANSLATION enmTranslation)
    3244 {
    3245     PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
    3246     int rc;
    3247 
    3248     Assert(pImage);
    3249 
    3250     if (pImage)
    3251     {
    3252         /** @todo maybe store this in the image descriptor */
    3253         pImage->enmTranslation = enmTranslation;
    3254         rc = VINF_SUCCESS;
    3255     }
    3256     else
    3257         rc = VERR_VDI_NOT_OPENED;
    3258     LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
    3259     return rc;
     3606        uImageFlags = 0;
     3607
     3608    LogFlow(("%s: returned %#x\n", __FUNCTION__, uImageFlags));
     3609    return uImageFlags;
    32603610}
    32613611
     
    33003650}
    33013651
    3302 static int vmdkGetComment(void *pBackendData, char *pszComment, size_t cbComment)
     3652static int vmdkGetComment(void *pBackendData, char *pszComment,
     3653                          size_t cbComment)
    33033654{
    33043655    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     
    34773828}
    34783829
     3830static void vmdkDump(void *pBackendData)
     3831{
     3832    PVMDKIMAGE pImage = (PVMDKIMAGE)pBackendData;
     3833
     3834    Assert(pImage);
     3835    if (pImage)
     3836    {
     3837        RTLogPrintf("Header: Geometry PCHS=%u/%u/%u LCHS=%u/%u/%u cbSector=%llu\n",
     3838                    pImage->PCHSGeometry.cCylinders, pImage->PCHSGeometry.cHeads, pImage->PCHSGeometry.cSectors,
     3839                    pImage->LCHSGeometry.cCylinders, pImage->LCHSGeometry.cHeads, pImage->LCHSGeometry.cSectors,
     3840                    VMDK_BYTE2SECTOR(pImage->cbSize));
     3841        RTLogPrintf("Header: uuidCreation={%Vuuid}\n", pImage->ImageUuid);
     3842        RTLogPrintf("Header: uuidModification={%Vuuid}\n", pImage->ModificationUuid);
     3843        RTLogPrintf("Header: uuidParent={%Vuuid}\n", pImage->ParentUuid);
     3844    }
     3845}
     3846
    34793847
    34803848VBOXHDDBACKEND g_VmdkBackend =
    34813849{
     3850    /* pszBackendName */
     3851    "VMDK",
    34823852    /* cbSize */
    34833853    sizeof(VBOXHDDBACKEND),
    34843854    /* pfnCheckIfValid */
    3485     NULL,
     3855    vmdkCheckIfValid,
    34863856    /* pfnOpen */
    34873857    vmdkOpen,
    34883858    /* pfnCreate */
    34893859    vmdkCreate,
     3860    /* pfnRename */
     3861    vmdkRename,
    34903862    /* pfnClose */
    34913863    vmdkClose,
     
    34963868    /* pfnFlush */
    34973869    vmdkFlush,
     3870    /* pfnGetVersion */
     3871    vmdkGetVersion,
    34983872    /* pfnGetImageType */
    34993873    vmdkGetImageType,
    35003874    /* pfnGetSize */
    35013875    vmdkGetSize,
    3502     /* pfnGetGeometry */
    3503     vmdkGetGeometry,
    3504     /* pfnSetGeometry */
    3505     vmdkSetGeometry,
    3506     /* pfnGetTranslation */
    3507     vmdkGetTranslation,
    3508     /* pfnSetTranslation */
    3509     vmdkSetTranslation,
     3876    /* pfnGetFileSize */
     3877    vmdkGetFileSize,
     3878    /* pfnGetPCHSGeometry */
     3879    vmdkGetPCHSGeometry,
     3880    /* pfnSetPCHSGeometry */
     3881    vmdkSetPCHSGeometry,
     3882    /* pfnGetLCHSGeometry */
     3883    vmdkGetLCHSGeometry,
     3884    /* pfnSetLCHSGeometry */
     3885    vmdkSetLCHSGeometry,
     3886    /* pfnGetImageFlags */
     3887    vmdkGetImageFlags,
    35103888    /* pfnGetOpenFlags */
    35113889    vmdkGetOpenFlags,
     
    35273905    vmdkGetParentUuid,
    35283906    /* pfnSetParentUuid */
    3529     vmdkSetParentUuid
     3907    vmdkSetParentUuid,
     3908    /* pfnDump */
     3909    vmdkDump
    35303910};
  • trunk/src/VBox/Devices/Storage/testcase/vditool.cpp

    r6285 r6291  
    253253    if (VBOX_SUCCESS(rc))
    254254    {
    255         rc = VDIDiskSetGeometry(pVdi, 0, 0, 0);
    256         if (VBOX_SUCCESS(rc))
    257             rc = VDIDiskSetTranslation(pVdi, PDMBIOSTRANSLATION_AUTO);
     255        PDMMEDIAGEOMETRY LCHSGeometry = {0, 0, 0};
     256        rc = VDIDiskSetLCHSGeometry(pVdi, &LCHSGeometry);
    258257    }
    259258    VDIDiskCloseImage(pVdi);
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp

    r6240 r6291  
    88
    99/*
    10  * Copyright (C) 2006-2007 innotek GmbH
     10 * Copyright (C) 2006-2008 innotek GmbH
    1111 *
    1212 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    570570    GEN_CHECK_OFF(ATADevState, fIrqPending);
    571571    GEN_CHECK_OFF(ATADevState, cMultSectors);
    572     GEN_CHECK_OFF(ATADevState, cCHSCylinders);
    573     GEN_CHECK_OFF(ATADevState, cCHSHeads);
    574     GEN_CHECK_OFF(ATADevState, cCHSSectors);
     572    GEN_CHECK_OFF(ATADevState, PCHSGeometry.cCylinders);
     573    GEN_CHECK_OFF(ATADevState, PCHSGeometry.cHeads);
     574    GEN_CHECK_OFF(ATADevState, PCHSGeometry.cSectors);
    575575    GEN_CHECK_OFF(ATADevState, cSectorsPerIRQ);
    576576    GEN_CHECK_OFF(ATADevState, cTotalSectors);
  • trunk/src/VBox/Main/HardDiskImpl.cpp

    r6173 r6291  
    36123612    CHECK_READY();
    36133613
    3614 /// @todo (r=dmik) will need this if we add suppord for differencing VMDKs
     3614/// @todo (r=dmik) will need this if we add support for differencing VMDKs
    36153615//
    36163616//     /* only a non-differencing image knows the logical size */
     
    37713771                mFilePathFull.raw());
    37723772
    3773 /// @todo (r=dmik) will need this if we add suppord for differencing VMDKs
     3773/// @todo (r=dmik) will need this if we add support for differencing VMDKs
    37743774//         if (isDifferencing())
    37753775//             return setError (E_FAIL,
     
    39403940    return E_NOTIMPL;
    39413941
    3942 /// @todo (r=dmik) will need this if we add suppord for differencing VMDKs
     3942/// @todo (r=dmik) will need this if we add support for differencing VMDKs
    39433943//  Use code from HVirtualDiskImage::cloneToImage as an example.
    39443944}
     
    39603960    return E_NOTIMPL;
    39613961
    3962 /// @todo (r=dmik) will need this if we add suppord for differencing VMDKs
     3962/// @todo (r=dmik) will need this if we add support for differencing VMDKs
    39633963//  Use code from HVirtualDiskImage::createDiffImage as an example.
    39643964}
     
    41234123        if (!mParent)
    41244124        {
    4125             uint64_t size = VDGetSize (mContainer);
     4125            uint64_t size = VDGetSize (mContainer, 0);
    41264126            /* convert to MBytes */
    41274127            mSize = size / 1024 / 1024;
     
    49594959        if (!mParent)
    49604960        {
    4961             uint64_t size = VDGetSize (mContainer);
     4961            uint64_t size = VDGetSize (mContainer, 0);
    49624962            /* convert to MBytes */
    49634963            mSize = size / 1024 / 1024;
     
    58235823        if (!mParent)
    58245824        {
    5825             uint64_t size = VDGetSize (mContainer);
     5825            uint64_t size = VDGetSize (mContainer, 0);
    58265826            /* convert to MBytes */
    58275827            mSize = size / 1024 / 1024;
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette