Index: /trunk/include/iprt/dvm.h
===================================================================
--- /trunk/include/iprt/dvm.h	(revision 85893)
+++ /trunk/include/iprt/dvm.h	(revision 85894)
@@ -298,5 +298,5 @@
  *
  * @returns IPRT status code.
- * @param   hVolMgr         The volume manager handler.
+ * @param   hVolMgr         The volume manager handle.
  * @param   off             The start offset to check for.
  * @param   cb              The range in bytes to check.
@@ -306,4 +306,54 @@
  */
 RTDECL(int) RTDvmMapQueryBlockStatus(RTDVM hVolMgr, uint64_t off, uint64_t cb, bool *pfAllocated);
+
+/**
+ * Partition/map table location information.
+ * @sa RTDvmMapQueryTableLocations
+ */
+typedef struct RTDVMTABLELOCATION
+{
+    /** The byte offset on the underlying media. */
+    uint64_t    off;
+    /** The table size in bytes. */
+    uint64_t    cb;
+    /** Number of padding bytes / free space between the actual table and
+     *  first partition. */
+    uint64_t    cbPadding;
+} RTDVMTABLELOCATION;
+/** Pointer to partition table location info. */
+typedef RTDVMTABLELOCATION *PRTDVMTABLELOCATION;
+/** Pointer to const partition table location info. */
+typedef RTDVMTABLELOCATION const *PCRTDVMTABLELOCATION;
+
+
+/** @name RTDVMMAPQTABLOC_F_XXX - Flags for RTDvmMapQueryTableLocations
+ * @{ */
+/** Make sure GPT includes the protective MBR. */
+#define RTDVMMAPQTABLOC_F_INCLUDE_LEGACY    RT_BIT_32(0)
+/** Valid flags.   */
+#define RTDVMMAPQTABLOC_F_VALID_MASK        UINT32_C(1)
+/** @} */
+
+/**
+ * Query the partition table locations.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_BUFFER_OVERFLOW if the table is too small, @a *pcActual will be
+ *          set to the required size.
+ * @retval  VERR_BUFFER_UNDERFLOW if the table is too big and @a pcActual is
+ *          NULL.
+ * @param   hVolMgr         The volume manager handle.
+ * @param   fFlags          Flags, see RTDVMMAPQTABLOC_F_XXX.
+ * @param   paLocations     Where to return the info.  This can be NULL if @a
+ *                          cLocations is zero and @a pcActual is given.
+ * @param   cLocations      The size of @a paLocations in items.
+ * @param   pcActual        Where to return the actual number of locations, or
+ *                          on VERR_BUFFER_OVERFLOW the necessary table size.
+ *                          Optional, when not specified the cLocations value
+ *                          must match exactly or it fails with
+ *                          VERR_BUFFER_UNDERFLOW.
+ */
+RTDECL(int) RTDvmMapQueryTableLocations(RTDVM hVolMgr, uint32_t fFlags,
+                                        PRTDVMTABLELOCATION paLocations, size_t cLocations, size_t *pcActual);
 
 /**
Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 85893)
+++ /trunk/include/iprt/mangling.h	(revision 85894)
@@ -834,4 +834,5 @@
 # define RTDvmMapQueryNextVolume                        RT_MANGLER(RTDvmMapQueryNextVolume)
 # define RTDvmMapQueryDiskUuid                          RT_MANGLER(RTDvmMapQueryDiskUuid)
+# define RTDvmMapQueryTableLocations                    RT_MANGLER(RTDvmMapQueryTableLocations)
 # define RTDvmVolumeRetain                              RT_MANGLER(RTDvmVolumeRetain)
 # define RTDvmVolumeRelease                             RT_MANGLER(RTDvmVolumeRelease)
Index: /trunk/src/VBox/Runtime/common/dvm/dvm.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvm.cpp	(revision 85893)
+++ /trunk/src/VBox/Runtime/common/dvm/dvm.cpp	(revision 85894)
@@ -627,4 +627,36 @@
 }
 
+RTDECL(int) RTDvmMapQueryTableLocations(RTDVM hVolMgr, uint32_t fFlags,
+                                        PRTDVMTABLELOCATION paLocations, size_t cLocations, size_t *pcActual)
+{
+    PRTDVMINTERNAL pThis = hVolMgr;
+
+    /*
+     * Input validation.
+     */
+    if (cLocations)
+    {
+        AssertPtrReturn(paLocations, VERR_INVALID_POINTER);
+        if (pcActual)
+        {
+            AssertPtrReturn(pcActual, VERR_INVALID_POINTER);
+            *pcActual = 0;
+        }
+    }
+    else
+    {
+        AssertPtrReturn(pcActual, VERR_INVALID_POINTER);
+        *pcActual = 0;
+    }
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(!(fFlags & ~RTDVMMAPQTABLOC_F_VALID_MASK), VERR_INVALID_FLAGS);
+
+    /*
+     * Pass it down to the format backend.
+     */
+    return pThis->pDvmFmtOps->pfnQueryTableLocations(pThis->hVolMgrFmt, fFlags, paLocations, cLocations, pcActual);
+}
+
 RTDECL(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol)
 {
Index: /trunk/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp	(revision 85893)
+++ /trunk/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp	(revision 85894)
@@ -442,4 +442,66 @@
 }
 
+/** @copydoc RTDVMFMTOPS::pfnQueryTableLocations */
+static DECLCALLBACK(int) rtDvmFmtBsdLblQueryTableLocations(RTDVMFMT hVolMgrFmt, uint32_t fFlags, PRTDVMTABLELOCATION paLocations,
+                                                           size_t cLocations, size_t *pcActual)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    /*
+     * The MBR if requested.
+     */
+    int     rc = VINF_SUCCESS;
+    size_t  iLoc = 0;
+    if (fFlags & RTDVMMAPQTABLOC_F_INCLUDE_LEGACY)
+    {
+        if (cLocations > 0)
+        {
+            paLocations[iLoc].off       = 0;
+            paLocations[iLoc].cb        = RTDVM_BSDLBL_LBA2BYTE(1, pThis->pDisk);
+            paLocations[iLoc].cbPadding = 0;
+        }
+        else
+            rc = VERR_BUFFER_OVERFLOW;
+        iLoc++;
+    }
+
+    /*
+     * The BSD lable.
+     */
+    if (cLocations > iLoc)
+    {
+        paLocations[iLoc].off = RTDVM_BSDLBL_LBA2BYTE(1, pThis->pDisk);
+        paLocations[iLoc].cb  = (sizeof(BsdLabel) + pThis->pDisk->cbSector - 1) / pThis->pDisk->cbSector * pThis->pDisk->cbSector;
+
+        uint32_t offFirstSector = pThis->pDisk->cbDisk / pThis->pDisk->cbSector;
+        for (unsigned i = 0; i < pThis->DiskLabel.cPartitions; i++)
+            if (   pThis->DiskLabel.aPartitions[i].cSectors
+                && pThis->DiskLabel.aPartitions[i].offSectorStart < offFirstSector)
+                offFirstSector =  pThis->DiskLabel.aPartitions[i].offSectorStart;
+
+        uint64_t offEnd = paLocations[iLoc].off + paLocations[iLoc].cb;
+        paLocations[iLoc].cbPadding = (uint64_t)offFirstSector * pThis->DiskLabel.cbSector;
+        if (paLocations[iLoc].cbPadding > offEnd)
+            paLocations[iLoc].cbPadding -= offEnd;
+        else
+            AssertFailedStmt(paLocations[iLoc].cbPadding = 0);
+    }
+    else
+        rc = VERR_BUFFER_OVERFLOW;
+    iLoc++;
+
+    /*
+     * Return values.
+     */
+    if (pcActual)
+        *pcActual = iLoc;
+    else if (cLocations != iLoc && RT_SUCCESS(rc))
+    {
+        RT_BZERO(&paLocations[iLoc], (cLocations - iLoc) * sizeof(paLocations[0]));
+        rc = VERR_BUFFER_UNDERFLOW;
+    }
+    return rc;
+}
+
 static DECLCALLBACK(void) rtDvmFmtBsdLblVolumeClose(RTDVMVOLUMEFMT hVolFmt)
 {
@@ -607,4 +669,6 @@
     /* pfnQueryNextVolume */
     rtDvmFmtBsdLblQueryNextVolume,
+    /* pfnQueryTableLocations */
+    rtDvmFmtBsdLblQueryTableLocations,
     /* pfnVolumeClose */
     rtDvmFmtBsdLblVolumeClose,
Index: /trunk/src/VBox/Runtime/common/dvm/dvmgpt.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvmgpt.cpp	(revision 85893)
+++ /trunk/src/VBox/Runtime/common/dvm/dvmgpt.cpp	(revision 85894)
@@ -463,4 +463,68 @@
 }
 
+/** @copydoc RTDVMFMTOPS::pfnQueryTableLocations */
+static DECLCALLBACK(int) rtDvmFmtGptQueryTableLocations(RTDVMFMT hVolMgrFmt, uint32_t fFlags, PRTDVMTABLELOCATION paLocations,
+                                                        size_t cLocations, size_t *pcActual)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    /*
+     * The MBR if requested.
+     */
+    int     rc = VINF_SUCCESS;
+    size_t  iLoc = 0;
+    if (fFlags & RTDVMMAPQTABLOC_F_INCLUDE_LEGACY)
+    {
+        if (cLocations > 0)
+        {
+            paLocations[iLoc].off       = 0;
+            paLocations[iLoc].cb        = RTDVM_GPT_LBA2BYTE(1, pThis->pDisk);
+            paLocations[iLoc].cbPadding = 0;
+        }
+        else
+            rc = VERR_BUFFER_OVERFLOW;
+        iLoc++;
+    }
+
+    /*
+     * The GPT.
+     */
+    if (cLocations > iLoc)
+    {
+        uint64_t const offEnd = (pThis->HdrRev1.cPartitionEntries * pThis->HdrRev1.cbPartitionEntry + pThis->pDisk->cbSector - 1)
+                              / pThis->pDisk->cbSector
+                              * pThis->pDisk->cbSector;
+        paLocations[iLoc].off       = RTDVM_GPT_LBA2BYTE(1, pThis->pDisk);
+        paLocations[iLoc].cb        = offEnd - paLocations[iLoc].off;
+
+        uint64_t uLbaFirstPart = pThis->pDisk->cbDisk / pThis->pDisk->cbSector;
+        for (unsigned i = 0; i < pThis->HdrRev1.cPartitionEntries; i++)
+            if (   pThis->paGptEntries[i].u64LbaFirst < uLbaFirstPart
+                && !RTUuidIsNull(&pThis->paGptEntries[i].UuidType))
+                uLbaFirstPart = pThis->paGptEntries[i].u64LbaFirst;
+
+        paLocations[iLoc].cbPadding = RTDVM_GPT_LBA2BYTE(uLbaFirstPart, pThis->pDisk);
+        if (paLocations[iLoc].cbPadding > offEnd)
+            paLocations[iLoc].cbPadding -= offEnd;
+        else
+            AssertFailedStmt(paLocations[iLoc].cbPadding = 0);
+    }
+    else
+        rc = VERR_BUFFER_OVERFLOW;
+    iLoc++;
+
+    /*
+     * Return values.
+     */
+    if (pcActual)
+        *pcActual = iLoc;
+    else if (cLocations != iLoc && RT_SUCCESS(rc))
+    {
+        RT_BZERO(&paLocations[iLoc], (cLocations - iLoc) * sizeof(paLocations[0]));
+        rc = VERR_BUFFER_UNDERFLOW;
+    }
+    return rc;
+}
+
 static DECLCALLBACK(void) rtDvmFmtGptVolumeClose(RTDVMVOLUMEFMT hVolFmt)
 {
@@ -650,4 +714,6 @@
     /* pfnQueryNextVolume */
     rtDvmFmtGptQueryNextVolume,
+    /* pfnQueryTableLocations */
+    rtDvmFmtGptQueryTableLocations,
     /* pfnVolumeClose */
     rtDvmFmtGptVolumeClose,
Index: /trunk/src/VBox/Runtime/common/dvm/dvmmbr.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvmmbr.cpp	(revision 85893)
+++ /trunk/src/VBox/Runtime/common/dvm/dvmmbr.cpp	(revision 85894)
@@ -732,4 +732,97 @@
 }
 
+/**
+ * Helper for rtDvmFmtMbrQueryTableLocations that calculates the padding and/or
+ * free space at @a off.
+ *
+ * Because nothing need to be sorted by start offset, we have to traverse all
+ * partition tables to determine this.
+ */
+static uint64_t rtDvmFmtMbrCalcTablePadding(PRTDVMFMTINTERNAL pThis, uint64_t off)
+{
+    uint64_t offNext = pThis->pDisk->cbDisk;
+    for (unsigned i = 0; i < 4; i++)
+    {
+        /* Check this primary entry */
+        uint64_t offCur = pThis->Primary.aEntries[i].offPart;
+        if (offCur >= off && offCur < offNext && pThis->Primary.aEntries[i].bType != 0)
+            offNext = offCur;
+
+        /* If it's an extended partition, check the chained ones too. */
+        for (PRTDVMMBRSECTOR pCur = pThis->Primary.aEntries[i].pChain;
+             pCur != NULL;
+             pCur->idxExtended != UINT8_MAX ? pCur->aEntries[pCur->idxExtended].pChain : NULL)
+        {
+            for (unsigned j = 0; j < 4; j++)
+            {
+                offCur = pCur->aEntries[j].offPart;
+                if (offCur >= off && offCur < offNext && pCur->aEntries[j].bType != 0)
+                    offNext = offCur;
+            }
+        }
+    }
+    Assert(offNext >= off);
+    return offNext - off;
+}
+
+/** @copydoc RTDVMFMTOPS::pfnQueryTableLocations */
+static DECLCALLBACK(int) rtDvmFmtMbrQueryTableLocations(RTDVMFMT hVolMgrFmt, uint32_t fFlags, PRTDVMTABLELOCATION paLocations,
+                                                        size_t cLocations, size_t *pcActual)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+    RT_NOREF(fFlags);
+
+    /*
+     * The MBR.
+     */
+    int     rc = VINF_SUCCESS;
+    size_t  iLoc = 0;
+    if (cLocations > 0)
+    {
+        paLocations[iLoc].off       = pThis->Primary.offOnDisk;
+        paLocations[iLoc].cb        = pThis->cbSector;
+        paLocations[iLoc].cbPadding = rtDvmFmtMbrCalcTablePadding(pThis, 0 + pThis->cbSector);
+    }
+    else
+        rc = VERR_BUFFER_OVERFLOW;
+    iLoc++;
+
+    /*
+     * Now do the extended partitions.
+     *
+     * Remember, we only support multiple in the primary MBR, only the first
+     * one is honored in the chained ones.
+     */
+    for (unsigned i = 0; i < 4; i++)
+    {
+        for (PRTDVMMBRSECTOR pCur = pThis->Primary.aEntries[i].pChain;
+             pCur != NULL;
+             pCur->idxExtended != UINT8_MAX ? pCur->aEntries[pCur->idxExtended].pChain : NULL)
+        {
+            if (cLocations > iLoc)
+            {
+                paLocations[iLoc].off       = pCur->offOnDisk;
+                paLocations[iLoc].cb        = pThis->cbSector;
+                paLocations[iLoc].cbPadding = rtDvmFmtMbrCalcTablePadding(pThis, pCur->offOnDisk + pThis->cbSector);
+            }
+            else
+                rc = VERR_BUFFER_OVERFLOW;
+            iLoc++;
+        }
+    }
+
+    /*
+     * Return values.
+     */
+    if (pcActual)
+        *pcActual = iLoc;
+    else if (cLocations != iLoc && RT_SUCCESS(rc))
+    {
+        RT_BZERO(&paLocations[iLoc], (cLocations - iLoc) * sizeof(paLocations[0]));
+        rc = VERR_BUFFER_UNDERFLOW;
+    }
+    return rc;
+}
+
 static DECLCALLBACK(void) rtDvmFmtMbrVolumeClose(RTDVMVOLUMEFMT hVolFmt)
 {
@@ -937,4 +1030,6 @@
     /* pfnQueryNextVolume */
     rtDvmFmtMbrQueryNextVolume,
+    /* pfnQueryTableLocations */
+    rtDvmFmtMbrQueryTableLocations,
     /* pfnVolumeClose */
     rtDvmFmtMbrVolumeClose,
Index: /trunk/src/VBox/Runtime/include/internal/dvm.h
===================================================================
--- /trunk/src/VBox/Runtime/include/internal/dvm.h	(revision 85893)
+++ /trunk/src/VBox/Runtime/include/internal/dvm.h	(revision 85894)
@@ -185,4 +185,27 @@
 
     /**
+     * Query the partition table locations.
+     *
+     * @returns IPRT status code.
+     * @retval  VERR_BUFFER_OVERFLOW if the table is too small, @a *pcActual will be
+     *          set to the required size.
+     * @retval  VERR_BUFFER_UNDERFLOW if the table is too big and @a pcActual is
+     *          NULL.
+     * @param   hVolMgrFmt      The format specific volume manager handle.
+     * @param   fFlags          Flags, see RTDVMMAPQTABLOC_F_XXX.
+     * @param   paLocations     Where to return the info. Ignored if @a cLocations
+     *                          is zero, then only @a pcActual matters.
+     * @param   cLocations      The size of @a paLocations in items.
+     * @param   pcActual        Where to return the actual number of locations, or
+     *                          on VERR_BUFFER_OVERFLOW the necessary table size.
+     *                          Optional, when not specified the cLocations value
+     *                          must match exactly or it fails with
+     *                          VERR_BUFFER_UNDERFLOW.
+     * @sa RTDvmMapQueryTableLocations
+     */
+    DECLCALLBACKMEMBER(int, pfnQueryTableLocations,(RTDVMFMT hVolMgrFmt, uint32_t fFlags, PRTDVMTABLELOCATION paLocations,
+                                                    size_t cLocations, size_t *pcActual));
+
+    /**
      * Closes a volume handle.
      *
