Index: trunk/src/VBox/Runtime/common/dvm/dvm.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dvm/dvm.cpp	(revision 36868)
+++ trunk/src/VBox/Runtime/common/dvm/dvm.cpp	(revision 36868)
@@ -0,0 +1,473 @@
+/* $Id$ */
+/** @file
+ * IPRT Disk Volume Management API (DVM) - generic code.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <iprt/types.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/dvm.h>
+#include <iprt/err.h>
+#include <iprt/asm.h>
+#include <iprt/string.h>
+#include "internal/dvm.h"
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+
+/**
+ * The internal volume manager structure.
+ */
+typedef struct RTDVMINTERNAL
+{
+    /** The DVM magic (RTDVM_MAGIC). */
+    uint32_t          u32Magic;
+    /** The disk descriptor. */
+    RTDVMDISK         DvmDisk;
+    /** Pointer to the backend operations table after a successful probe. */
+    PCRTDVMFMTOPS     pDvmFmtOps;
+    /** The format specific volume manager data. */
+    RTDVMFMT          hVolMgrFmt;
+    /** Reference counter. */
+    uint32_t volatile cRefs;
+} RTDVMINTERNAL;
+/** Pointer to an internal volume manager. */
+typedef RTDVMINTERNAL *PRTDVMINTERNAL;
+
+/**
+ * The internal volume structure.
+ */
+typedef struct RTDVMVOLUMEINTERNAL
+{
+    /** The DVM volume magic (RTDVMVOLUME_MAGIC). */
+    uint32_t          u32Magic;
+    /** Pointer to the owning volume manager. */
+    PRTDVMINTERNAL    pVolMgr;
+    /** Format specific volume data. */
+    RTDVMVOLUMEFMT    hVolFmt;
+    /** Reference counter. */
+    uint32_t volatile cRefs;
+} RTDVMVOLUMEINTERNAL;
+/** Pointer to an internal volume. */
+typedef RTDVMVOLUMEINTERNAL *PRTDVMVOLUMEINTERNAL;
+
+/*******************************************************************************
+*  Global variables                                                            *
+*******************************************************************************/
+extern RTDVMFMTOPS g_DvmFmtMbr;
+extern RTDVMFMTOPS g_DvmFmtGpt;
+
+/**
+ * Supported volume formats.
+ */
+static PCRTDVMFMTOPS g_aDvmFmts[] =
+{
+    &g_DvmFmtMbr,
+    &g_DvmFmtGpt
+};
+
+/**
+ * Descriptions of the volume types.
+ */
+static const char * g_apcszDvmVolTypes[] =
+{
+    "Invalid",
+    "Unknown",
+    "NTFS",
+    "FAT16",
+    "FAT32",
+    "Linux swap",
+    "Linux native",
+    "Linux LVM",
+    "Linux SoftRaid",
+    "FreeBSD",
+    "NetBSD",
+    "OpenBSD",
+    "Mac OS X HFS or HFS+",
+    "Solaris"
+};
+
+RTDECL(int) RTDvmCreate(PRTDVM phVolMgr, PFNDVMREAD pfnRead,
+                        PFNDVMWRITE pfnWrite, uint64_t cbDisk,
+                        uint64_t cbSector, void *pvUser)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMINTERNAL pThis;
+
+    pThis = (PRTDVMINTERNAL)RTMemAllocZ(sizeof(RTDVMINTERNAL));
+    if (VALID_PTR(pThis))
+    {
+        pThis->u32Magic         = RTDVM_MAGIC;
+        pThis->DvmDisk.cbDisk   = cbDisk;
+        pThis->DvmDisk.cbSector = cbSector;
+        pThis->DvmDisk.pvUser   = pvUser;
+        pThis->DvmDisk.pfnRead  = pfnRead;
+        pThis->DvmDisk.pfnWrite = pfnWrite;
+        pThis->pDvmFmtOps       = NULL;
+        pThis->hVolMgrFmt       = NIL_RTDVMFMT;
+        pThis->cRefs            = 1;
+        *phVolMgr = pThis;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+RTDECL(uint32_t) RTDvmRetain(RTDVM hVolMgr)
+{
+    PRTDVMINTERNAL pThis = hVolMgr;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
+
+    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+    AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+    return cRefs;
+}
+
+/**
+ * Destroys a volume manager handle.
+ *
+ * @param   pThis               The volume manager to destroy.
+ */
+static void rtDvmDestroy(PRTDVMINTERNAL pThis)
+{
+    if (pThis->hVolMgrFmt != NIL_RTDVMFMT)
+    {
+        AssertPtr(pThis->pDvmFmtOps);
+
+        /* Let the backend do it's own cleanup first. */
+        pThis->pDvmFmtOps->pfnClose(pThis->hVolMgrFmt);
+        pThis->hVolMgrFmt = NIL_RTDVMFMT;
+    }
+
+    pThis->DvmDisk.cbDisk   = 0;
+    pThis->DvmDisk.pvUser   = NULL;
+    pThis->DvmDisk.pfnRead  = NULL;
+    pThis->DvmDisk.pfnWrite = NULL;
+    pThis->u32Magic         = RTDVM_MAGIC_DEAD;
+    RTMemFree(pThis);
+}
+
+RTDECL(uint32_t) RTDvmRelease(RTDVM hVolMgr)
+{
+    PRTDVMINTERNAL pThis = hVolMgr;
+    if (pThis == NIL_RTDVM)
+        return 0;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
+
+    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+    AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+    if (cRefs == 0)
+        rtDvmDestroy(pThis);
+    return cRefs;
+}
+
+RTDECL(int) RTDvmMapOpen(RTDVM hVolMgr)
+{
+    int            rc = VINF_SUCCESS;
+    uint32_t       uScoreMax = RTDVM_MATCH_SCORE_UNSUPPORTED;
+    PCRTDVMFMTOPS  pDvmFmtOpsMatch = NULL;
+    PRTDVMINTERNAL pThis = hVolMgr;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_INVALID_HANDLE);
+
+    Assert(!pThis->pDvmFmtOps);
+
+    for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
+    {
+        uint32_t uScore;
+        PCRTDVMFMTOPS pDvmFmtOps = g_aDvmFmts[i];
+
+        rc = pDvmFmtOps->pfnProbe(&pThis->DvmDisk, &uScore);
+        if (   RT_SUCCESS(rc)
+            && uScore > uScoreMax)
+        {
+            pDvmFmtOpsMatch = pDvmFmtOps;
+            uScoreMax       = uScore;
+        }
+        else if (RT_FAILURE(rc))
+            break;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (uScoreMax > RTDVM_MATCH_SCORE_UNSUPPORTED)
+        {
+            AssertPtr(pDvmFmtOpsMatch);
+
+            /* Open the format. */
+            rc = pDvmFmtOpsMatch->pfnOpen(&pThis->DvmDisk, &pThis->hVolMgrFmt);
+            if (RT_SUCCESS(rc))
+                pThis->pDvmFmtOps = pDvmFmtOpsMatch;
+        }
+        else
+            rc = VERR_NOT_FOUND;
+    }
+
+    return rc;
+}
+
+RTDECL(int) RTDvmMapInitialize(RTDVM hVolMgr, const char *pszFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMINTERNAL pThis = hVolMgr;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertPtrReturn(pszFmt, VERR_INVALID_POINTER);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_INVALID_HANDLE);
+
+    for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
+    {
+        PCRTDVMFMTOPS pDvmFmtOps = g_aDvmFmts[i];
+
+        if (!RTStrCmp(pDvmFmtOps->pcszFmt, pszFmt))
+        {
+            rc = pDvmFmtOps->pfnInitialize(&pThis->DvmDisk, &pThis->hVolMgrFmt);
+            if (RT_SUCCESS(rc))
+                pThis->pDvmFmtOps = pDvmFmtOps;
+
+            break;
+        }
+    }
+
+    return rc;
+}
+
+RTDECL(const char *) RTDvmMapGetFormat(RTDVM hVolMgr)
+{
+    PRTDVMINTERNAL pThis = hVolMgr;
+    AssertPtrReturn(pThis, NULL);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, NULL);
+    AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, NULL);
+
+    return pThis->pDvmFmtOps->pcszFmt;
+}
+
+RTDECL(uint32_t) RTDvmMapGetValidVolumes(RTDVM hVolMgr)
+{
+    PRTDVMINTERNAL pThis = hVolMgr;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
+    AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
+
+    return pThis->pDvmFmtOps->pfnGetValidVolumes(pThis->hVolMgrFmt);
+}
+
+RTDECL(uint32_t) RTDvmMapGetMaxVolumes(RTDVM hVolMgr)
+{
+    PRTDVMINTERNAL pThis = hVolMgr;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
+    AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
+
+    return pThis->pDvmFmtOps->pfnGetMaxVolumes(pThis->hVolMgrFmt);
+}
+
+static int rtDvmVolumeCreate(PRTDVMINTERNAL pThis, RTDVMVOLUMEFMT hVolFmt,
+                             PRTDVMVOLUME phVol)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMVOLUMEINTERNAL pVol = NULL;
+
+    pVol = (PRTDVMVOLUMEINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEINTERNAL));
+    if (VALID_PTR(pVol))
+    {
+        pVol->u32Magic = RTDVMVOLUME_MAGIC;
+        pVol->cRefs    = 1;
+        pVol->pVolMgr  = pThis;
+        pVol->hVolFmt  = hVolFmt;
+
+        /* Reference the volume manager. */
+        RTDvmRetain(pThis);
+        *phVol = pVol;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+RTDECL(int) RTDvmMapQueryFirstVolume(RTDVM hVolMgr, PRTDVMVOLUME phVol)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMINTERNAL pThis = hVolMgr;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
+    AssertPtrReturn(phVol, VERR_INVALID_POINTER);
+
+    RTDVMVOLUMEFMT hVolFmt = NIL_RTDVMVOLUMEFMT;
+    rc = pThis->pDvmFmtOps->pfnQueryFirstVolume(pThis->hVolMgrFmt, &hVolFmt);
+    if (RT_SUCCESS(rc))
+    {
+        rc = rtDvmVolumeCreate(pThis, hVolFmt, phVol);
+        if (RT_FAILURE(rc))
+            pThis->pDvmFmtOps->pfnVolumeClose(hVolFmt);
+    }
+
+    return rc;
+}
+
+RTDECL(int) RTDvmMapQueryNextVolume(RTDVM hVolMgr, RTDVMVOLUME hVol, PRTDVMVOLUME phVolNext)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMINTERNAL       pThis = hVolMgr;
+    PRTDVMVOLUMEINTERNAL pVol = hVol;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
+    AssertPtrReturn(pVol, VERR_INVALID_HANDLE);
+    AssertReturn(pVol->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
+    AssertPtrReturn(phVolNext, VERR_INVALID_POINTER);
+
+    RTDVMVOLUMEFMT hVolFmtNext = NIL_RTDVMVOLUMEFMT;
+    rc = pThis->pDvmFmtOps->pfnQueryNextVolume(pThis->hVolMgrFmt, pVol->hVolFmt, &hVolFmtNext);
+    if (RT_SUCCESS(rc))
+    {
+        rc = rtDvmVolumeCreate(pThis, hVolFmtNext, phVolNext);
+        if (RT_FAILURE(rc))
+            pThis->pDvmFmtOps->pfnVolumeClose(hVolFmtNext);
+    }
+
+    return rc;
+}
+
+RTDECL(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
+
+    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+    AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+    return cRefs;
+}
+
+/**
+ * Destroys a volume handle.
+ *
+ * @param   pThis               The volume to destroy.
+ */
+static void rtDvmVolumeDestroy(PRTDVMVOLUMEINTERNAL pThis)
+{
+    PRTDVMINTERNAL pVolMgr = pThis->pVolMgr;
+
+    AssertPtr(pVolMgr);
+
+    /* Close the volume. */
+    pVolMgr->pDvmFmtOps->pfnVolumeClose(pThis->hVolFmt);
+
+    pThis->u32Magic = RTDVMVOLUME_MAGIC_DEAD;
+    pThis->pVolMgr  = NULL;
+    pThis->hVolFmt  = NIL_RTDVMVOLUMEFMT;
+    RTMemFree(pThis);
+
+    /* Release the reference of the volume manager. */
+    RTDvmRelease(pVolMgr);
+}
+
+RTDECL(uint32_t) RTDvmVolumeRelease(RTDVMVOLUME hVol)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    if (pThis == NIL_RTDVMVOLUME)
+        return 0;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
+
+    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+    AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+    if (cRefs == 0)
+        rtDvmVolumeDestroy(pThis);
+    return cRefs;
+}
+
+RTDECL(uint64_t) RTDvmVolumeGetSize(RTDVMVOLUME hVol)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    AssertPtrReturn(pThis, 0);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, 0);
+
+    return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetSize(pThis->hVolFmt);
+}
+
+RTDECL(int) RTDvmVolumeQueryName(RTDVMVOLUME hVol, char **ppszVolName)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(ppszVolName, VERR_INVALID_POINTER);
+
+    return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryName(pThis->hVolFmt, ppszVolName);
+}
+
+RTDECL(RTDVMVOLTYPE) RTDvmVolumeGetType(RTDVMVOLUME hVol)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    AssertPtrReturn(pThis, RTDVMVOLTYPE_INVALID);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, RTDVMVOLTYPE_INVALID);
+
+    return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetType(pThis->hVolFmt);
+}
+
+RTDECL(uint64_t) RTDvmVolumeGetFlags(RTDVMVOLUME hVol)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    AssertPtrReturn(pThis, UINT64_MAX);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT64_MAX);
+
+    return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetFlags(pThis->hVolFmt);
+}
+
+RTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(pvBuf, VERR_INVALID_POINTER);
+    AssertReturn(cbRead > 0, VERR_INVALID_PARAMETER);
+
+    return pThis->pVolMgr->pDvmFmtOps->pfnVolumeRead(pThis->hVolFmt, off, pvBuf, cbRead);
+}
+
+RTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite)
+{
+    PRTDVMVOLUMEINTERNAL pThis = hVol;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(pvBuf, VERR_INVALID_POINTER);
+    AssertReturn(cbWrite > 0, VERR_INVALID_PARAMETER);
+
+    return pThis->pVolMgr->pDvmFmtOps->pfnVolumeWrite(pThis->hVolFmt, off, pvBuf, cbWrite);
+}
+
+RTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType)
+{
+    AssertReturn(enmVolType >= RTDVMVOLTYPE_INVALID && enmVolType < RTDVMVOLTYPE_32BIT_HACK, NULL);
+
+    return g_apcszDvmVolTypes[enmVolType];
+}
Index: trunk/src/VBox/Runtime/common/dvm/dvmgpt.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dvm/dvmgpt.cpp	(revision 36868)
+++ trunk/src/VBox/Runtime/common/dvm/dvmgpt.cpp	(revision 36868)
@@ -0,0 +1,524 @@
+/* $Id$ */
+/** @file
+ * IPRT Disk Volume Management API (DVM) - GPT format backend.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <iprt/types.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/dvm.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+#include "internal/dvm.h"
+
+/** The GPT signature. */
+#define RTDVM_GPT_SIGNATURE "EFI PART"
+
+/**
+ * GPT on disk header.
+ */
+#pragma pack(1)
+typedef struct GptHdr
+{
+    /** Signature ("EFI PART"). */
+    char     abSignature[8];
+    /** Revision. */
+    uint32_t u32Revision;
+    /** Header size. */
+    uint32_t cbHeader;
+    /** CRC of header. */
+    uint32_t u32Crc;
+} GptHdr;
+/** Pointer to a GPT header. */
+typedef struct GptHdr *PGptHdr;
+#pragma pack()
+AssertCompileSize(GptHdr, 20);
+
+/**
+ * Complete GPT table header for revision 1.0.
+ */
+#pragma pack(1)
+typedef struct GptHdrRev1
+{
+    /** Header. */
+    GptHdr   Hdr;
+    /** Reserved. */
+    uint32_t u32Reserved;
+    /** Current LBA. */
+    uint64_t u64LbaCurrent;
+    /** Backup LBA. */
+    uint64_t u64LbaBackup;
+    /** First usable LBA for partitions. */
+    uint64_t u64LbaFirstPartition;
+    /** Last usable LBA for partitions. */
+    uint64_t u64LbaLastPartition;
+    /** Disk UUID. */
+    RTUUID   DiskUuid;
+    /** LBA of first partition entry. */
+    uint64_t u64LbaPartitionEntries;
+    /** Number of partition entries. */
+    uint32_t cPartitionEntries;
+    /** Partition entry size. */
+    uint32_t cbPartitionEntry;
+    /** CRC of partition entries. */
+    uint32_t u32CrcPartitionEntries;
+} GptHdrRev1;
+/** Pointer to a revision 1.0 GPT header. */
+typedef GptHdrRev1 *PGptHdrRev1;
+#pragma pack()
+AssertCompileSize(GptHdrRev1, 92);
+
+/**
+ * GPT partition table entry.
+ */
+#pragma pack(1)
+typedef struct GptEntry
+{
+    /** Partition type UUID. */
+    RTUUID   UuidType;
+    /** Partition UUID. */
+    RTUUID   UuidPartition;
+    /** First LBA. */
+    uint64_t u64LbaFirst;
+    /** Last LBA. */
+    uint64_t u64LbaLast;
+    /** Attribute flags. */
+    uint64_t u64Flags;
+    /** Partition name (UTF-16LE code units). */
+    RTUTF16  aPartitionName[36];
+} GptEntry;
+/** Pointer to a GPT entry. */
+typedef struct GptEntry *PGptEntry;
+#pragma pack()
+AssertCompileSize(GptEntry, 128);
+
+/** Partition flags - System partition. */
+#define RTDVM_GPT_ENTRY_SYSTEM          RT_BIT_64(0)
+/** Partition flags - Partition is readonly. */
+#define RTDVM_GPT_ENTRY_READONLY        RT_BIT_64(60)
+/** Partition flags - Partition is hidden. */
+#define RTDVM_GPT_ENTRY_HIDDEN          RT_BIT_64(62)
+/** Partition flags - Don't automount this partition. */
+#define RTDVM_GPT_ENTRY_NO_AUTOMOUNT    RT_BIT_64(63)
+
+/**
+ * GPT volume manager data.
+ */
+typedef struct RTDVMFMTINTERNAL
+{
+    /** Pointer to the underlying disk. */
+    PCRTDVMDISK     pDisk;
+    /** GPT header. */
+    GptHdrRev1      HdrRev1;
+    /** GPT array. */
+    PGptEntry       paGptEntries;
+    /** Number of occupied partition entries. */
+    uint32_t        cPartitions;
+} RTDVMFMTINTERNAL;
+/** Pointer to the MBR volume manager. */
+typedef RTDVMFMTINTERNAL *PRTDVMFMTINTERNAL;
+
+/**
+ * GPT volume data.
+ */
+typedef struct RTDVMVOLUMEFMTINTERNAL
+{
+    /** Pointer to the volume manager. */
+    PRTDVMFMTINTERNAL pVolMgr;
+    /** Partition table entry index. */
+    uint32_t          idxEntry;
+    /** Start offset of the volume. */
+    uint64_t          offStart;
+    /** Size of the volume. */
+    uint64_t          cbVolume;
+    /** Pointer to the GPT entry in the array. */
+    PGptEntry         pGptEntry;
+} RTDVMVOLUMEFMTINTERNAL;
+/** Pointer to an MBR volume. */
+typedef RTDVMVOLUMEFMTINTERNAL *PRTDVMVOLUMEFMTINTERNAL;
+
+/**
+ * GPT partition type to DVM volume type mapping entry.
+ */
+
+typedef struct RTDVMGPTPARTTYPE2VOLTYPE
+{
+    /** Type UUID. */
+    const char       *pcszUuid;
+    /** DVM volume type. */
+    RTDVMVOLTYPE      enmVolType;
+} RTDVMGPTPARTTYPE2VOLTYPE;
+/** Pointer to a MBR FS Type to volume type mapping entry. */
+typedef RTDVMGPTPARTTYPE2VOLTYPE *PRTDVMGPTPARTTYPE2VOLTYPE;
+
+/** Converts a LBA number to the byte offset. */
+#define RTDVM_GPT_LBA2BYTE(lba, disk) ((lba) * (disk)->cbSector)
+/** Converts a Byte offset to the LBA number. */
+#define RTDVM_GPT_BYTE2LBA(lba, disk) ((lba) / (disk)->cbSector)
+
+/**
+ * Mapping of partition types to DVM volume types.
+ *
+ * From http://en.wikipedia.org/wiki/GUID_Partition_Table
+ */
+static const RTDVMGPTPARTTYPE2VOLTYPE g_aPartType2DvmVolTypes[] =
+{
+    {"0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", RTDVMVOLTYPE_LINUX_SWAP},
+    {"EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", RTDVMVOLTYPE_LINUX_NATIVE},
+    {"E6D6D379-F507-44C2-A23C-238F2A3DF928", RTDVMVOLTYPE_LINUX_LVM},
+    {"A19D880F-05FC-4D3B-A006-743F0F84911E", RTDVMVOLTYPE_LINUX_SOFTRAID},
+
+    {"83BD6B9D-7F41-11DC-BE0B-001560B84F0F", RTDVMVOLTYPE_FREEBSD}, /* Boot */
+    {"516E7CB4-6ECF-11D6-8FF8-00022D09712B", RTDVMVOLTYPE_FREEBSD}, /* Data */
+    {"516E7CB5-6ECF-11D6-8FF8-00022D09712B", RTDVMVOLTYPE_FREEBSD}, /* Swap */
+    {"516E7CB6-6ECF-11D6-8FF8-00022D09712B", RTDVMVOLTYPE_FREEBSD}, /* UFS */
+    {"516E7CB8-6ECF-11D6-8FF8-00022D09712B", RTDVMVOLTYPE_FREEBSD}, /* Vinum */
+    {"516E7CBA-6ECF-11D6-8FF8-00022D09712B", RTDVMVOLTYPE_FREEBSD}, /* ZFS */
+
+    {"49F48D32-B10E-11DC-B99B-0019D1879648", RTDVMVOLTYPE_NETBSD}, /* Swap */
+    {"49F48D5A-B10E-11DC-B99B-0019D1879648", RTDVMVOLTYPE_NETBSD}, /* FFS */
+    {"49F48D82-B10E-11DC-B99B-0019D1879648", RTDVMVOLTYPE_NETBSD}, /* LFS */
+    {"49F48DAA-B10E-11DC-B99B-0019D1879648", RTDVMVOLTYPE_NETBSD}, /* Raid */
+    {"2DB519C4-B10F-11DC-B99B-0019D1879648", RTDVMVOLTYPE_NETBSD}, /* Concatenated */
+    {"2DB519EC-B10F-11DC-B99B-0019D1879648", RTDVMVOLTYPE_NETBSD}, /* Encrypted */
+
+    {"48465300-0000-11AA-AA11-00306543ECAC", RTDVMVOLTYPE_MAC_OSX_HFS},
+
+    {"6A82CB45-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* Boot */
+    {"6A85CF4D-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* Root */
+    {"6A87C46F-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* Swap */
+    {"6A8B642B-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* Backup */
+    {"6A898CC3-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* /usr */
+    {"6A8EF2E9-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* /var */
+    {"6A90BA39-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* /home */
+    {"6A9283A5-1DD2-11B2-99A6-080020736631", RTDVMVOLTYPE_SOLARIS}, /* Alternate sector */
+};
+
+DECLCALLBACK(int) dvmFmtGptProbe(PCRTDVMDISK pDisk, uint32_t *puScore)
+{
+    int rc = VINF_SUCCESS;
+    GptHdr Hdr;
+
+    *puScore = RTDVM_MATCH_SCORE_UNSUPPORTED;
+
+    if (dvmDiskGetSectors(pDisk) >= 2)
+    {
+        /* Read from the disk and check for the signature. */
+        rc = dvmDiskRead(pDisk, RTDVM_GPT_LBA2BYTE(1, pDisk), &Hdr, sizeof(GptHdr));
+        if (   RT_SUCCESS(rc)
+            && !strncmp(&Hdr.abSignature[0], RTDVM_GPT_SIGNATURE, RT_ELEMENTS(Hdr.abSignature))
+            && RT_LE2H_U32(Hdr.u32Revision) == 0x00010000
+            && RT_LE2H_U32(Hdr.cbHeader)    == sizeof(GptHdrRev1))
+            *puScore = RTDVM_MATCH_SCORE_PERFECT;
+    }
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtGptOpen(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMFMTINTERNAL pThis = NULL;
+
+    pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
+    if (VALID_PTR(pThis))
+    {
+        pThis->pDisk       = pDisk;
+        pThis->cPartitions = 0;
+
+        /* Read the complete GPT header and convert to host endianess. */
+        rc = dvmDiskRead(pDisk, RTDVM_GPT_LBA2BYTE(1, pDisk), &pThis->HdrRev1, sizeof(pThis->HdrRev1));
+        if (RT_SUCCESS(rc))
+        {
+            pThis->HdrRev1.Hdr.u32Revision        = RT_LE2H_U32(pThis->HdrRev1.Hdr.u32Revision);
+            pThis->HdrRev1.Hdr.cbHeader           = RT_LE2H_U32(pThis->HdrRev1.Hdr.cbHeader);
+            pThis->HdrRev1.Hdr.u32Crc             = RT_LE2H_U32(pThis->HdrRev1.Hdr.u32Crc);
+            pThis->HdrRev1.u64LbaCurrent          = RT_LE2H_U64(pThis->HdrRev1.u64LbaCurrent);
+            pThis->HdrRev1.u64LbaBackup           = RT_LE2H_U64(pThis->HdrRev1.u64LbaBackup);
+            pThis->HdrRev1.u64LbaFirstPartition   = RT_LE2H_U64(pThis->HdrRev1.u64LbaFirstPartition);
+            pThis->HdrRev1.u64LbaLastPartition    = RT_LE2H_U64(pThis->HdrRev1.u64LbaLastPartition);
+            /** @todo: Disk UUID */
+            pThis->HdrRev1.u64LbaPartitionEntries = RT_LE2H_U64(pThis->HdrRev1.u64LbaPartitionEntries);
+            pThis->HdrRev1.cPartitionEntries      = RT_LE2H_U32(pThis->HdrRev1.cPartitionEntries);
+            pThis->HdrRev1.cbPartitionEntry       = RT_LE2H_U32(pThis->HdrRev1.cbPartitionEntry);
+            pThis->HdrRev1.u32CrcPartitionEntries = RT_LE2H_U32(pThis->HdrRev1.u32CrcPartitionEntries);
+
+            if (pThis->HdrRev1.cbPartitionEntry == sizeof(GptEntry))
+            {
+                pThis->paGptEntries = (PGptEntry)RTMemAllocZ(pThis->HdrRev1.cPartitionEntries * pThis->HdrRev1.cbPartitionEntry);
+                if (VALID_PTR(pThis->paGptEntries))
+                {
+                    rc = dvmDiskRead(pDisk, RTDVM_GPT_LBA2BYTE(pThis->HdrRev1.u64LbaPartitionEntries, pDisk),
+                                     pThis->paGptEntries, pThis->HdrRev1.cPartitionEntries * pThis->HdrRev1.cbPartitionEntry);
+                    if (RT_SUCCESS(rc))
+                    {
+                        /* Count the occupied entries. */
+                        for (unsigned i = 0; i < pThis->HdrRev1.cPartitionEntries; i++)
+                            if (!RTUuidIsNull(&pThis->paGptEntries[i].UuidType))
+                            {
+                                /* Convert to host endianess. */
+                                /** @todo: Uuids */
+                                pThis->paGptEntries[i].u64LbaFirst = RT_LE2H_U64(pThis->paGptEntries[i].u64LbaFirst);
+                                pThis->paGptEntries[i].u64LbaLast  = RT_LE2H_U64(pThis->paGptEntries[i].u64LbaLast);
+                                pThis->paGptEntries[i].u64Flags    = RT_LE2H_U64(pThis->paGptEntries[i].u64Flags);
+                                for (unsigned cwc = 0; cwc < RT_ELEMENTS(pThis->paGptEntries[i].aPartitionName); cwc++)
+                                    pThis->paGptEntries[i].aPartitionName[cwc] = RT_LE2H_U16(pThis->paGptEntries[i].aPartitionName[cwc]);
+
+                                pThis->cPartitions++;
+                            }
+                    }
+
+                    if (RT_FAILURE(rc))
+                        RTMemFree(pThis->paGptEntries);
+                }
+                else
+                    rc = VERR_NO_MEMORY;
+            }
+            else
+                rc = VERR_NOT_SUPPORTED;
+
+            if (RT_SUCCESS(rc))
+                *phVolMgrFmt = pThis;
+            else
+                RTMemFree(pThis);
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtGptInitialize(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
+{
+    return VERR_NOT_IMPLEMENTED;
+}
+
+DECLCALLBACK(void) dvmFmtGptClose(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    pThis->pDisk = NULL;
+    memset(&pThis->HdrRev1, 0, sizeof(pThis->HdrRev1));
+    RTMemFree(pThis->paGptEntries);
+
+    pThis->paGptEntries = NULL;
+    RTMemFree(pThis);
+}
+
+DECLCALLBACK(uint32_t) dvmFmtGptGetValidVolumes(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    return pThis->cPartitions;
+}
+
+DECLCALLBACK(uint32_t) dvmFmtGptGetMaxVolumes(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    return pThis->HdrRev1.cPartitionEntries;
+}
+
+/**
+ * Creates a new volume.
+ *
+ * @returns IPRT status code.
+ * @param   pThis         The MBR volume manager data.
+ * @param   pGptEntry     The GPT entry.
+ * @param   idx           The index in the partition array.
+ * @param   phVolFmt      Where to store the volume data on success.
+ */
+static int dvmFmtMbrVolumeCreate(PRTDVMFMTINTERNAL pThis, PGptEntry pGptEntry,
+                                 uint32_t idx, PRTDVMVOLUMEFMT phVolFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMVOLUMEFMTINTERNAL pVol = (PRTDVMVOLUMEFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEFMTINTERNAL));
+
+    if (VALID_PTR(pVol))
+    {
+        pVol->pVolMgr    = pThis;
+        pVol->idxEntry   = idx;
+        pVol->pGptEntry  = pGptEntry;
+        pVol->offStart   = RTDVM_GPT_LBA2BYTE(pGptEntry->u64LbaFirst, pThis->pDisk);
+        pVol->cbVolume   = RTDVM_GPT_LBA2BYTE(pGptEntry->u64LbaLast - pGptEntry->u64LbaFirst + 1, pThis->pDisk);
+
+        *phVolFmt = pVol;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtGptQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    if (pThis->cPartitions != 0)
+    {
+        PGptEntry pGptEntry = &pThis->paGptEntries[0];
+
+        /* Search for the first non empty entry. */
+        for (unsigned i = 0; i < pThis->HdrRev1.cPartitionEntries; i++)
+        {
+            if (!RTUuidIsNull(&pGptEntry->UuidType))
+            {
+                rc = dvmFmtMbrVolumeCreate(pThis, pGptEntry, i, phVolFmt);
+                break;
+            }
+            pGptEntry++;
+        }
+    }
+    else
+        rc = VERR_DVM_MAP_EMPTY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtGptQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
+{
+    int rc = VERR_DVM_MAP_NO_VOLUME;
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    PGptEntry pGptEntry = pVol->pGptEntry + 1;
+
+    for (unsigned i = pVol->idxEntry + 1; i < pThis->HdrRev1.cPartitionEntries; i++)
+    {
+        if (!RTUuidIsNull(&pGptEntry->UuidType))
+        {
+            rc = dvmFmtMbrVolumeCreate(pThis, pGptEntry, i, phVolFmtNext);
+            break;
+        }
+        pGptEntry++;
+    }
+
+    return rc;
+}
+
+DECLCALLBACK(void) dvmFmtGptVolumeClose(RTDVMVOLUMEFMT hVolFmt)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    pVol->pVolMgr    = NULL;
+    pVol->offStart   = 0;
+    pVol->cbVolume   = 0;
+    pVol->pGptEntry  = NULL;
+
+    RTMemFree(pVol);
+}
+
+DECLCALLBACK(uint64_t) dvmFmtGptVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    return pVol->cbVolume;
+}
+
+DECLCALLBACK(int) dvmFmtGptVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    int rc = VINF_SUCCESS;
+
+    *ppszVolName = NULL;
+    rc = RTUtf16ToUtf8Ex(&pVol->pGptEntry->aPartitionName[0], RT_ELEMENTS(pVol->pGptEntry->aPartitionName),
+                         ppszVolName, 0, NULL);
+
+    return rc;
+}
+
+DECLCALLBACK(RTDVMVOLTYPE) dvmFmtGptVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
+{
+    RTDVMVOLTYPE enmVolType = RTDVMVOLTYPE_UNKNOWN;
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    for (unsigned i = 0; i < RT_ELEMENTS(g_aPartType2DvmVolTypes); i++)
+        if (!RTUuidCompareStr(&pVol->pGptEntry->UuidType, g_aPartType2DvmVolTypes[i].pcszUuid))
+        {
+            enmVolType = g_aPartType2DvmVolTypes[i].enmVolType;
+            break;
+        }
+
+    return enmVolType;
+}
+
+DECLCALLBACK(uint64_t) dvmFmtGptVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
+{
+    NOREF(hVolFmt); /* No supported flags for now. */
+    return 0;
+}
+
+DECLCALLBACK(int) dvmFmtGptVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    AssertReturn(off + cbRead <= pVol->cbVolume, VERR_INVALID_PARAMETER);
+
+    return dvmDiskRead(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbRead);
+}
+
+DECLCALLBACK(int) dvmFmtGptVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    AssertReturn(off + cbWrite <= pVol->cbVolume, VERR_INVALID_PARAMETER);
+
+    return dvmDiskWrite(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbWrite);
+}
+
+RTDVMFMTOPS g_DvmFmtGpt = 
+{
+    /* pcszFmt */
+    "GPT",
+    /* pfnProbe */
+    dvmFmtGptProbe,
+    /* pfnOpen */
+    dvmFmtGptOpen,
+    /* pfnInitialize */
+    dvmFmtGptInitialize,
+    /* pfnClose */
+    dvmFmtGptClose,
+    /* pfnGetValidVolumes */
+    dvmFmtGptGetValidVolumes,
+    /* pfnGetMaxVolumes */
+    dvmFmtGptGetMaxVolumes,
+    /* pfnQueryFirstVolume */
+    dvmFmtGptQueryFirstVolume,
+    /* pfnQueryNextVolume */
+    dvmFmtGptQueryNextVolume,
+    /* pfnVolumeClose */
+    dvmFmtGptVolumeClose,
+    /* pfnVolumeGetSize */
+    dvmFmtGptVolumeGetSize,
+    /* pfnVolumeQueryName */
+    dvmFmtGptVolumeQueryName,
+    /* pfnVolumeGetType */
+    dvmFmtGptVolumeGetType,
+    /* pfnVolumeGetFlags */
+    dvmFmtGptVolumeGetFlags,
+    /* pfnVolumeRead */
+    dvmFmtGptVolumeRead,
+    /* pfnVolumeWrite */
+    dvmFmtGptVolumeWrite
+};
+
Index: trunk/src/VBox/Runtime/common/dvm/dvmmbr.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/dvm/dvmmbr.cpp	(revision 36868)
+++ trunk/src/VBox/Runtime/common/dvm/dvmmbr.cpp	(revision 36868)
@@ -0,0 +1,397 @@
+/* $Id$ */
+/** @file
+ * IPRT Disk Volume Management API (DVM) - MBR format backend.
+ */
+
+/*
+ * Copyright (C) 2011 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include <iprt/types.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/dvm.h>
+#include <iprt/string.h>
+#include "internal/dvm.h"
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+
+/**
+ * MBR volume manager data.
+ */
+typedef struct RTDVMFMTINTERNAL
+{
+    /** Pointer to the underlying disk. */
+    PCRTDVMDISK     pDisk;
+    /** Number of initialized partitions. */
+    uint32_t        cPartitions;
+    /** The raw MBR data. */
+    uint8_t         abMbr[512];
+} RTDVMFMTINTERNAL;
+/** Pointer to the MBR volume manager. */
+typedef RTDVMFMTINTERNAL *PRTDVMFMTINTERNAL;
+
+/**
+ * MBR volume data.
+ */
+typedef struct RTDVMVOLUMEFMTINTERNAL
+{
+    /** Pointer to the volume manager. */
+    PRTDVMFMTINTERNAL pVolMgr;
+    /** Partition table entry index. */
+    uint32_t          idxEntry;
+    /** Start offset of the volume. */
+    uint64_t          offStart;
+    /** Size of the volume. */
+    uint64_t          cbVolume;
+    /** Pointer to the raw partition table entry. */
+    uint8_t          *pbMbrEntry;
+} RTDVMVOLUMEFMTINTERNAL;
+/** Pointer to an MBR volume. */
+typedef RTDVMVOLUMEFMTINTERNAL *PRTDVMVOLUMEFMTINTERNAL;
+
+/**
+ * MBR FS type to DVM volume type mapping entry.
+ */
+
+typedef struct RTDVMMBRFS2VOLTYPE
+{
+    /** MBR FS Id. */
+    uint8_t           bFsId;
+    /** DVM volume type. */
+    RTDVMVOLTYPE      enmVolType;
+} RTDVMMBRFS2VOLTYPE;
+/** Pointer to a MBR FS Type to volume type mapping entry. */
+typedef RTDVMMBRFS2VOLTYPE *PRTDVMMBRFS2VOLTYPE;
+
+/**
+ * Mapping of FS types to DVM volume types.
+ *
+ * From http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+ */
+static const RTDVMMBRFS2VOLTYPE g_aFs2DvmVolTypes[] =
+{
+    {0x06, RTDVMVOLTYPE_FAT16},
+    {0x07, RTDVMVOLTYPE_NTFS}, /* Used for exFAT too but NTFS is more common. */
+    {0x0b, RTDVMVOLTYPE_FAT32},
+    {0x0c, RTDVMVOLTYPE_FAT32},
+    {0x82, RTDVMVOLTYPE_LINUX_SWAP},
+    {0x83, RTDVMVOLTYPE_LINUX_NATIVE},
+    {0x8e, RTDVMVOLTYPE_LINUX_LVM},
+    {0xa5, RTDVMVOLTYPE_FREEBSD},
+    {0xa9, RTDVMVOLTYPE_NETBSD},
+    {0xa6, RTDVMVOLTYPE_OPENBSD},
+    {0xaf, RTDVMVOLTYPE_MAC_OSX_HFS},
+    {0xbf, RTDVMVOLTYPE_SOLARIS},
+    {0xfd, RTDVMVOLTYPE_LINUX_SOFTRAID}
+};
+
+DECLCALLBACK(int) dvmFmtMbrProbe(PCRTDVMDISK pDisk, uint32_t *puScore)
+{
+    int rc = VINF_SUCCESS;
+    uint8_t abMbr[512];
+
+    *puScore = RTDVM_MATCH_SCORE_UNSUPPORTED;
+
+    if (pDisk->cbDisk >= 512)
+    {
+        /* Read from the disk and check for the 0x55aa signature at the end. */
+        rc = dvmDiskRead(pDisk, 0, &abMbr[0], sizeof(abMbr));
+        if (   RT_SUCCESS(rc)
+            && abMbr[510] == 0x55
+            && abMbr[511] == 0xaa)
+            *puScore = RTDVM_MATCH_SCORE_SUPPORTED; /* Not perfect because GPTs have a protective MBR. */
+    }
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtMbrOpen(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMFMTINTERNAL pThis = NULL;
+
+    pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
+    if (VALID_PTR(pThis))
+    {
+        pThis->pDisk       = pDisk;
+        pThis->cPartitions = 0;
+
+        /* Read the MBR and count the valid partition entries. */
+        rc = dvmDiskRead(pDisk, 0, &pThis->abMbr[0], sizeof(pThis->abMbr));
+        if (RT_SUCCESS(rc))
+        {
+            uint8_t *pbMbrEntry = &pThis->abMbr[446];
+
+            Assert(pThis->abMbr[510] == 0x55 && pThis->abMbr[511] == 0xaa);
+
+            for (unsigned i = 0; i < 4; i++)
+            {
+                /* The entry is unused if the type contains 0x00. */
+                if (pbMbrEntry[4] != 0x00)
+                    pThis->cPartitions++;
+
+                pbMbrEntry += 16;
+            }
+
+            *phVolMgrFmt = pThis;
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtMbrInitialize(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMFMTINTERNAL pThis = NULL;
+
+    pThis = (PRTDVMFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMFMTINTERNAL));
+    if (VALID_PTR(pThis))
+    {
+        /* Setup a new MBR and write it to the disk. */
+        memset(&pThis->abMbr[0], 0, sizeof(pThis->abMbr));
+        pThis->abMbr[510] = 0x55;
+        pThis->abMbr[511] = 0xaa;
+
+        rc = dvmDiskWrite(pDisk, 0, &pThis->abMbr[0], sizeof(pThis->abMbr));
+
+        if (RT_SUCCESS(rc))
+        {
+            pThis->pDisk       = pDisk;
+            pThis->cPartitions = 0;
+            *phVolMgrFmt = pThis;
+        }
+        else
+            RTMemFree(pThis);
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+DECLCALLBACK(void) dvmFmtMbrClose(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    pThis->pDisk       = NULL;
+    pThis->cPartitions = 0;
+    memset(&pThis->abMbr[0], 0, sizeof(pThis->abMbr));
+    RTMemFree(pThis);
+}
+
+DECLCALLBACK(uint32_t) dvmFmtMbrGetValidVolumes(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    return pThis->cPartitions;
+}
+
+DECLCALLBACK(uint32_t) dvmFmtMbrGetMaxVolumes(RTDVMFMT hVolMgrFmt)
+{
+    NOREF(hVolMgrFmt);
+    return 4; /** @todo: Add support for EBR? */
+}
+
+/**
+ * Creates a new volume.
+ *
+ * @returns IPRT status code.
+ * @param   pThis         The MBR volume manager data.
+ * @param   pbMbrEntry    The raw MBR entry data.
+ * @param   idx           The index in the partition table.
+ * @param   phVolFmt      Where to store the volume data on success.
+ */
+static int dvmFmtMbrVolumeCreate(PRTDVMFMTINTERNAL pThis, uint8_t *pbMbrEntry,
+                                 uint32_t idx, PRTDVMVOLUMEFMT phVolFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMVOLUMEFMTINTERNAL pVol = (PRTDVMVOLUMEFMTINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEFMTINTERNAL));
+
+    if (VALID_PTR(pVol))
+    {
+        pVol->pVolMgr    = pThis;
+        pVol->idxEntry   = idx;
+        pVol->pbMbrEntry = pbMbrEntry;
+        pVol->offStart   = *(uint32_t *)&pbMbrEntry[0x08] * pThis->pDisk->cbSector;
+        pVol->cbVolume   = *(uint32_t *)&pbMbrEntry[0x0c] * pThis->pDisk->cbSector;
+
+        *phVolFmt = pVol;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtMbrQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    if (pThis->cPartitions != 0)
+    {
+        uint8_t *pbMbrEntry = &pThis->abMbr[446];
+
+        /* Search for the first non empty entry. */
+        for (unsigned i = 0; i < 4; i++)
+        {
+            if (pbMbrEntry[0x04] != 0x00)
+            {
+                rc = dvmFmtMbrVolumeCreate(pThis, pbMbrEntry, i, phVolFmt);
+                break;
+            }
+            pbMbrEntry += 16;
+        }
+    }
+    else
+        rc = VERR_DVM_MAP_EMPTY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) dvmFmtMbrQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
+{
+    int rc = VERR_DVM_MAP_NO_VOLUME;
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    uint8_t *pbMbrEntry = pVol->pbMbrEntry + 16;
+
+    for (unsigned i = pVol->idxEntry + 1; i < 4; i++)
+    {
+        if (pbMbrEntry[0x04] != 0x00)
+        {
+            rc = dvmFmtMbrVolumeCreate(pThis, pbMbrEntry, i, phVolFmtNext);
+            break;
+        }
+        pbMbrEntry += 16;
+    }
+
+    return rc;
+}
+
+DECLCALLBACK(void) dvmFmtMbrVolumeClose(RTDVMVOLUMEFMT hVolFmt)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    pVol->pVolMgr    = NULL;
+    pVol->offStart   = 0;
+    pVol->cbVolume   = 0;
+    pVol->pbMbrEntry = NULL;
+
+    RTMemFree(pVol);
+}
+
+DECLCALLBACK(uint64_t) dvmFmtMbrVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    return pVol->cbVolume;
+}
+
+DECLCALLBACK(int) dvmFmtMbrVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
+{
+    NOREF(hVolFmt);
+    return VERR_NOT_SUPPORTED;
+}
+
+DECLCALLBACK(RTDVMVOLTYPE) dvmFmtMbrVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
+{
+    RTDVMVOLTYPE enmVolType = RTDVMVOLTYPE_UNKNOWN;
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    for (unsigned i = 0; i < RT_ELEMENTS(g_aFs2DvmVolTypes); i++)
+        if (pVol->pbMbrEntry[0x04] == g_aFs2DvmVolTypes[i].bFsId)
+        {
+            enmVolType = g_aFs2DvmVolTypes[i].enmVolType;
+            break;
+        }
+
+    return enmVolType;
+}
+
+DECLCALLBACK(uint64_t) dvmFmtMbrVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
+{
+    uint64_t fFlags = 0;
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    if (pVol->pbMbrEntry[0x00] & 0x80)
+        fFlags |= DVMVOLUME_FLAGS_BOOTABLE | DVMVOLUME_FLAGS_ACTIVE;
+
+    return fFlags;
+}
+
+DECLCALLBACK(int) dvmFmtMbrVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    AssertReturn(off + cbRead <= pVol->cbVolume, VERR_INVALID_PARAMETER);
+
+    return dvmDiskRead(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbRead);
+}
+
+DECLCALLBACK(int) dvmFmtMbrVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    AssertReturn(off + cbWrite <= pVol->cbVolume, VERR_INVALID_PARAMETER);
+
+    return dvmDiskWrite(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbWrite);
+}
+
+RTDVMFMTOPS g_DvmFmtMbr = 
+{
+    /* pcszFmt */
+    "MBR",
+    /* pfnProbe */
+    dvmFmtMbrProbe,
+    /* pfnOpen */
+    dvmFmtMbrOpen,
+    /* pfnInitialize */
+    dvmFmtMbrInitialize,
+    /* pfnClose */
+    dvmFmtMbrClose,
+    /* pfnGetValidVolumes */
+    dvmFmtMbrGetValidVolumes,
+    /* pfnGetMaxVolumes */
+    dvmFmtMbrGetMaxVolumes,
+    /* pfnQueryFirstVolume */
+    dvmFmtMbrQueryFirstVolume,
+    /* pfnQueryNextVolume */
+    dvmFmtMbrQueryNextVolume,
+    /* pfnVolumeClose */
+    dvmFmtMbrVolumeClose,
+    /* pfnVolumeGetSize */
+    dvmFmtMbrVolumeGetSize,
+    /* pfnVolumeQueryName */
+    dvmFmtMbrVolumeQueryName,
+    /* pfnVolumeGetType */
+    dvmFmtMbrVolumeGetType,
+    /* pfnVolumeGetFlags */
+    dvmFmtMbrVolumeGetFlags,
+    /* pfnVolumeRead */
+    dvmFmtMbrVolumeRead,
+    /* pfnVolumeWrite */
+    dvmFmtMbrVolumeWrite
+};
+
