Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 37269)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 37270)
@@ -279,4 +279,5 @@
 	common/dbg/dbgmodnm.cpp \
 	common/dvm/dvm.cpp \
+	common/dvm/dvmbsdlabel.cpp \
 	common/dvm/dvmgpt.cpp \
 	common/dvm/dvmmbr.cpp \
Index: /trunk/src/VBox/Runtime/common/dvm/dvm.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvm.cpp	(revision 37269)
+++ /trunk/src/VBox/Runtime/common/dvm/dvm.cpp	(revision 37270)
@@ -83,4 +83,5 @@
 extern RTDVMFMTOPS g_rtDvmFmtMbr;
 extern RTDVMFMTOPS g_rtDvmFmtGpt;
+extern RTDVMFMTOPS g_rtDvmFmtBsdLbl;
 
 /**
@@ -90,5 +91,6 @@
 {
     &g_rtDvmFmtMbr,
-    &g_rtDvmFmtGpt
+    &g_rtDvmFmtGpt,
+    &g_rtDvmFmtBsdLbl
 };
 
@@ -233,5 +235,5 @@
         }
         else
-            rc = VERR_NOT_FOUND;
+            rc = VERR_NOT_SUPPORTED;
     }
 
Index: /trunk/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp	(revision 37270)
+++ /trunk/src/VBox/Runtime/common/dvm/dvmbsdlabel.cpp	(revision 37270)
@@ -0,0 +1,517 @@
+/* $Id$ */
+/** @file
+ * IPRT Disk Volume Management API (DVM) - BSD disklabel 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                                                    *
+*******************************************************************************/
+
+/*
+ * Below are the on disk structures of a bsd disklabel as found in
+ * /usr/include/sys/disklabel.h from a FreeBSD system.
+ *
+ * Everything is stored in little endian on the disk.
+ */
+
+/** BSD disklabel magic. */
+#define RTDVM_BSDLBL_MAGIC          UINT32_C(0x82564557)
+/** Maximum number of partitions in the label. */
+#define RTDVM_BSDLBL_MAX_PARTITIONS 8
+
+/**
+ * A BSD disk label partition.
+ */
+#pragma pack(1)
+typedef struct BsdLabelPartition
+{
+    /** Number of sectors in the partition. */
+    uint32_t             cSectors;
+    /** Start sector. */
+    uint32_t             offSectorStart;
+    /** Filesystem fragment size. */
+    uint32_t             cbFsFragment;
+    /** Filesystem type. */
+    uint8_t              bFsType;
+    /** Filesystem fragments per block. */
+    uint8_t              cFsFragmentsPerBlock;
+    /** Filesystem cylinders per group. */
+    uint16_t             cFsCylPerGroup;
+} BsdLabelPartition;
+#pragma pack()
+AssertCompileSize(BsdLabelPartition, 16);
+/** Pointer to a BSD disklabel partition structure. */
+typedef BsdLabelPartition *PBsdLabelPartition;
+
+/**
+ * On disk BSD label structure.
+ */
+#pragma pack(1)
+typedef struct BsdLabel
+{
+    /** Magic identifying the BSD disk label. */
+    uint32_t             u32Magic;
+    /** Drive type */
+    uint16_t             u16DriveType;
+    /** Subtype depending on the drive type above. */
+    uint16_t             u16SubType;
+    /** Type name. */
+    uint8_t              abTypeName[16];
+    /** Pack identifier. */
+    uint8_t              abPackName[16];
+    /** Number of bytes per sector. */
+    uint32_t             cbSector;
+    /** Number of sectors per track. */
+    uint32_t             cSectorsPerTrack;
+    /** Number of tracks per cylinder. */
+    uint32_t             cTracksPerCylinder;
+    /** Number of data cylinders pre unit. */
+    uint32_t             cDataCylindersPerUnit;
+    /** Number of data sectors per cylinder. */
+    uint32_t             cDataSectorsPerCylinder;
+    /** Number of data sectors per unit (unit as in disk drive?). */
+    uint32_t             cSectorsPerUnit;
+    /** Number of spare sectors per track. */
+    uint16_t             cSpareSectorsPerTrack;
+    /** Number of spare sectors per cylinder. */
+    uint16_t             cSpareSectorsPerCylinder;
+    /** Number of alternate cylinders per unit. */
+    uint32_t             cSpareCylindersPerUnit;
+    /** Rotational speed of the disk drive in rotations per minute. */
+    uint16_t             cRotationsPerMinute;
+    /** Sector interleave. */
+    uint16_t             uSectorInterleave;
+    /** Sector 0 skew, per track. */
+    uint16_t             uSectorSkewPerTrack;
+    /** Sector 0 skew, per cylinder. */
+    uint16_t             uSectorSkewPerCylinder;
+    /** Head switch time in us. */
+    uint32_t             usHeadSwitch;
+    /** Time of a track-to-track seek in us. */
+    uint32_t             usTrackSeek;
+    /** Flags. */
+    uint32_t             fFlags;
+    /** Drive type sepcific information. */
+    uint32_t             au32DriveData[5];
+    /** Reserved. */
+    uint32_t             au32Reserved[5];
+    /** The magic number again. */
+    uint32_t             u32Magic2;
+    /** Checksum (xor of the whole structure). */
+    uint16_t             u16ChkSum;
+    /** Number of partitions in the array. */
+    uint16_t             cPartitions;
+    /** Boot area size in bytes. */
+    uint32_t             cbBootArea;
+    /** Maximum size of the filesystem super block. */
+    uint32_t             cbFsSuperBlock;
+    /** The partition array. */
+    BsdLabelPartition    aPartitions[RTDVM_BSDLBL_MAX_PARTITIONS];
+} BsdLabel;
+#pragma pack()
+AssertCompileSize(BsdLabel, 148 + RTDVM_BSDLBL_MAX_PARTITIONS * 16);
+/** Pointer to a BSD disklabel structure. */
+typedef BsdLabel *PBsdLabel;
+
+/**
+ * BSD disk label volume manager data.
+ */
+typedef struct RTDVMFMTINTERNAL
+{
+    /** Pointer to the underlying disk. */
+    PCRTDVMDISK     pDisk;
+    /** Number of used partitions. */
+    uint32_t        cPartitions;
+    /** Saved BSD disklabel structure. */
+    BsdLabel        DiskLabel;
+} 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. */
+    PBsdLabelPartition  pBsdPartitionEntry;
+} RTDVMVOLUMEFMTINTERNAL;
+/** Pointer to an MBR volume. */
+typedef RTDVMVOLUMEFMTINTERNAL *PRTDVMVOLUMEFMTINTERNAL;
+
+/** Converts a LBA number to the byte offset. */
+#define RTDVM_BSDLBL_LBA2BYTE(lba, disk) ((lba) * (disk)->cbSector)
+/** Converts a Byte offset to the LBA number. */
+#define RTDVM_BSDLBL_BYTE2LBA(lba, disk) ((lba) / (disk)->cbSector)
+
+/**
+ * Calculates the checksum of the entire bsd disklabel structure.
+ *
+ * @returns The checksum.
+ * @param   pBsdLabel    BSD disklabel to get teh checksum for.
+ */
+static uint16_t rtDvmFmtBsdLblDiskLabelChkSum(PBsdLabel pBsdLabel)
+{
+    uint16_t uChkSum = 0;
+    uint16_t *pCurr = (uint16_t *)pBsdLabel;
+    uint16_t *pEnd  = (uint16_t *)&pBsdLabel->aPartitions[pBsdLabel->cPartitions];
+
+    while (pCurr < pEnd)
+        uChkSum ^= *pCurr++;
+
+    return uChkSum;
+}
+
+/**
+ * Converts a partition entry to the host endianness.
+ *
+ * @returns nothing.
+ * @param   pPartition    The partition to decode.
+ */
+static void rtDvmFmtBsdLblDiskLabelDecodePartition(PBsdLabelPartition pPartition)
+{
+    pPartition->cSectors       = RT_LE2H_U32(pPartition->cSectors);
+    pPartition->offSectorStart = RT_LE2H_U32(pPartition->offSectorStart);
+    pPartition->cbFsFragment   = RT_LE2H_U32(pPartition->cbFsFragment);
+    pPartition->cFsCylPerGroup = RT_LE2H_U16(pPartition->cFsCylPerGroup);
+}
+
+/**
+ * Converts the on disk BSD label to the host endianness.
+ *
+ * @returns Whether the given label structure is a valid BSD disklabel.
+ * @param   pBsdLabel    Pointer to the BSD disklabel to decode.
+ */
+static bool rtDvmFmtBsdLblDiskLabelDecode(PBsdLabel pBsdLabel)
+{
+    pBsdLabel->u32Magic                 = RT_LE2H_U32(pBsdLabel->u32Magic);
+    pBsdLabel->u16DriveType             = RT_LE2H_U16(pBsdLabel->u16DriveType);
+    pBsdLabel->u16SubType               = RT_LE2H_U16(pBsdLabel->u16SubType);
+    pBsdLabel->cbSector                 = RT_LE2H_U32(pBsdLabel->cbSector);
+    pBsdLabel->cSectorsPerTrack         = RT_LE2H_U32(pBsdLabel->cSectorsPerTrack);
+    pBsdLabel->cTracksPerCylinder       = RT_LE2H_U32(pBsdLabel->cTracksPerCylinder);
+    pBsdLabel->cDataCylindersPerUnit    = RT_LE2H_U32(pBsdLabel->cDataCylindersPerUnit);
+    pBsdLabel->cDataSectorsPerCylinder  = RT_LE2H_U32(pBsdLabel->cDataSectorsPerCylinder);
+    pBsdLabel->cSectorsPerUnit          = RT_LE2H_U32(pBsdLabel->cSectorsPerUnit);
+    pBsdLabel->cSpareSectorsPerTrack    = RT_LE2H_U16(pBsdLabel->cSpareSectorsPerTrack);
+    pBsdLabel->cSpareSectorsPerCylinder = RT_LE2H_U16(pBsdLabel->cSpareSectorsPerCylinder);
+    pBsdLabel->cSpareCylindersPerUnit   = RT_LE2H_U32(pBsdLabel->cSpareCylindersPerUnit);
+    pBsdLabel->cRotationsPerMinute      = RT_LE2H_U16(pBsdLabel->cRotationsPerMinute);
+    pBsdLabel->uSectorInterleave        = RT_LE2H_U16(pBsdLabel->uSectorInterleave);
+    pBsdLabel->uSectorSkewPerTrack      = RT_LE2H_U16(pBsdLabel->uSectorSkewPerTrack);
+    pBsdLabel->uSectorSkewPerCylinder   = RT_LE2H_U16(pBsdLabel->uSectorSkewPerCylinder);
+    pBsdLabel->usHeadSwitch             = RT_LE2H_U16(pBsdLabel->usHeadSwitch);
+    pBsdLabel->usTrackSeek              = RT_LE2H_U16(pBsdLabel->usTrackSeek);
+    pBsdLabel->fFlags                   = RT_LE2H_U32(pBsdLabel->fFlags);
+
+    for (unsigned i = 0; i < RT_ELEMENTS(pBsdLabel->au32DriveData); i++)
+        pBsdLabel->au32DriveData[i] = RT_LE2H_U32(pBsdLabel->au32DriveData[i]);
+    for (unsigned i = 0; i < RT_ELEMENTS(pBsdLabel->au32Reserved); i++)
+        pBsdLabel->au32Reserved[i] = RT_LE2H_U32(pBsdLabel->au32Reserved[i]);
+
+    pBsdLabel->u32Magic2                = RT_LE2H_U32(pBsdLabel->u32Magic2);
+    pBsdLabel->u16ChkSum                = RT_LE2H_U16(pBsdLabel->u16ChkSum);
+    pBsdLabel->cPartitions              = RT_LE2H_U16(pBsdLabel->cPartitions);
+    pBsdLabel->cbBootArea               = RT_LE2H_U32(pBsdLabel->cbBootArea);
+    pBsdLabel->cbFsSuperBlock           = RT_LE2H_U32(pBsdLabel->cbFsSuperBlock);
+
+    /* Check the magics now. */
+    if (   pBsdLabel->u32Magic    != RTDVM_BSDLBL_MAGIC
+        || pBsdLabel->u32Magic2   != RTDVM_BSDLBL_MAGIC
+        || pBsdLabel->cPartitions != RTDVM_BSDLBL_MAX_PARTITIONS)
+        return false;
+
+    /* Convert the partitions array. */
+    for (unsigned i = 0; i < RT_ELEMENTS(pBsdLabel->aPartitions); i++)
+        rtDvmFmtBsdLblDiskLabelDecodePartition(&pBsdLabel->aPartitions[i]);
+
+    /* Check the checksum now. */
+    uint16_t u16ChkSumSaved = pBsdLabel->u16ChkSum;
+
+    pBsdLabel->u16ChkSum = 0;
+    if (u16ChkSumSaved != rtDvmFmtBsdLblDiskLabelChkSum(pBsdLabel))
+        return false;
+
+    pBsdLabel->u16ChkSum = u16ChkSumSaved;
+    return true;
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblProbe(PCRTDVMDISK pDisk, uint32_t *puScore)
+{
+    BsdLabel DiskLabel;
+    int rc = VINF_SUCCESS;
+
+    *puScore = RTDVM_MATCH_SCORE_UNSUPPORTED;
+
+    if (pDisk->cbDisk >= sizeof(BsdLabel))
+    {
+        /* Read from the disk and check for the disk label structure. */
+        rc = rtDvmDiskRead(pDisk, RTDVM_BSDLBL_LBA2BYTE(1, pDisk), &DiskLabel, sizeof(BsdLabel));
+        if (   RT_SUCCESS(rc)
+            && rtDvmFmtBsdLblDiskLabelDecode(&DiskLabel))
+            *puScore = RTDVM_MATCH_SCORE_PERFECT;
+    }
+    return rc;
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblOpen(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 from the disk and check for the disk label structure. */
+        rc = rtDvmDiskRead(pDisk, RTDVM_BSDLBL_LBA2BYTE(1, pDisk), &pThis->DiskLabel, sizeof(BsdLabel));
+        if (   RT_SUCCESS(rc)
+            && rtDvmFmtBsdLblDiskLabelDecode(&pThis->DiskLabel))
+        {
+            /* Count number of used entries. */
+            for (unsigned i = 0; i < pThis->DiskLabel.cPartitions; i++)
+                if (pThis->DiskLabel.aPartitions[i].cSectors)
+                    pThis->cPartitions++;
+
+            *phVolMgrFmt = pThis;
+        }
+        else
+        {
+            RTMemFree(pThis);
+            rc = VERR_INVALID_MAGIC;
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblInitialize(PCRTDVMDISK pDisk, PRTDVMFMT phVolMgrFmt)
+{
+    return VERR_NOT_IMPLEMENTED;
+}
+
+DECLCALLBACK(void) rtDvmFmtBsdLblClose(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    pThis->pDisk       = NULL;
+    pThis->cPartitions = 0;
+    memset(&pThis->DiskLabel, 0, sizeof(BsdLabel));
+    RTMemFree(pThis);
+}
+
+DECLCALLBACK(uint32_t) rtDvmFmtBsdLblGetValidVolumes(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+    return pThis->cPartitions;
+}
+
+DECLCALLBACK(uint32_t) rtDvmFmtBsdLblGetMaxVolumes(RTDVMFMT hVolMgrFmt)
+{
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+    return pThis->DiskLabel.cPartitions;
+}
+
+/**
+ * Creates a new volume.
+ *
+ * @returns IPRT status code.
+ * @param   pThis         The MBR volume manager data.
+ * @param   pbBsdLblEntry    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 rtDvmFmtBsdLblVolumeCreate(PRTDVMFMTINTERNAL pThis, PBsdLabelPartition pBsdPartitionEntry,
+                                    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->pBsdPartitionEntry = pBsdPartitionEntry;
+        pVol->offStart           = pBsdPartitionEntry->offSectorStart * pThis->DiskLabel.cbSector;
+        pVol->cbVolume           = pBsdPartitionEntry->cSectors * pThis->DiskLabel.cbSector;
+
+        *phVolFmt = pVol;
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblQueryFirstVolume(RTDVMFMT hVolMgrFmt, PRTDVMVOLUMEFMT phVolFmt)
+{
+    int rc = VINF_SUCCESS;
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+
+    if (pThis->cPartitions != 0)
+    {
+        /* Search for the first non empty entry. */
+        for (unsigned i = 0; i < pThis->DiskLabel.cPartitions; i++)
+        {
+            if (pThis->DiskLabel.aPartitions[i].cSectors)
+            {
+                rc = rtDvmFmtBsdLblVolumeCreate(pThis, &pThis->DiskLabel.aPartitions[i],
+                                              i, phVolFmt);
+                break;
+            }
+        }
+    }
+    else
+        rc = VERR_DVM_MAP_EMPTY;
+
+    return rc;
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblQueryNextVolume(RTDVMFMT hVolMgrFmt, RTDVMVOLUMEFMT hVolFmt, PRTDVMVOLUMEFMT phVolFmtNext)
+{
+    int rc = VERR_DVM_MAP_NO_VOLUME;
+    PRTDVMFMTINTERNAL pThis = hVolMgrFmt;
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    PBsdLabelPartition pBsdPartitionEntry = pVol->pBsdPartitionEntry + 1;
+
+    for (unsigned i = pVol->idxEntry + 1; i < pThis->DiskLabel.cPartitions; i++)
+    {
+        if (pBsdPartitionEntry->cSectors)
+        {
+            rc = rtDvmFmtBsdLblVolumeCreate(pThis, pBsdPartitionEntry, i, phVolFmtNext);
+            break;
+        }
+        pBsdPartitionEntry++;
+    }
+
+    return rc;
+}
+
+DECLCALLBACK(void) rtDvmFmtBsdLblVolumeClose(RTDVMVOLUMEFMT hVolFmt)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    pVol->pVolMgr            = NULL;
+    pVol->offStart           = 0;
+    pVol->cbVolume           = 0;
+    pVol->pBsdPartitionEntry = NULL;
+
+    RTMemFree(pVol);
+}
+
+DECLCALLBACK(uint64_t) rtDvmFmtBsdLblVolumeGetSize(RTDVMVOLUMEFMT hVolFmt)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+
+    return pVol->cbVolume;
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblVolumeQueryName(RTDVMVOLUMEFMT hVolFmt, char **ppszVolName)
+{
+    NOREF(hVolFmt);
+    return VERR_NOT_SUPPORTED;
+}
+
+DECLCALLBACK(RTDVMVOLTYPE) rtDvmFmtBsdLblVolumeGetType(RTDVMVOLUMEFMT hVolFmt)
+{
+    return RTDVMVOLTYPE_UNKNOWN;
+}
+
+DECLCALLBACK(uint64_t) rtDvmFmtBsdLblVolumeGetFlags(RTDVMVOLUMEFMT hVolFmt)
+{
+    NOREF(hVolFmt);
+    return 0;
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblVolumeRead(RTDVMVOLUMEFMT hVolFmt, uint64_t off, void *pvBuf, size_t cbRead)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    AssertReturn(off + cbRead <= pVol->cbVolume, VERR_INVALID_PARAMETER);
+
+    return rtDvmDiskRead(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbRead);
+}
+
+DECLCALLBACK(int) rtDvmFmtBsdLblVolumeWrite(RTDVMVOLUMEFMT hVolFmt, uint64_t off, const void *pvBuf, size_t cbWrite)
+{
+    PRTDVMVOLUMEFMTINTERNAL pVol = hVolFmt;
+    AssertReturn(off + cbWrite <= pVol->cbVolume, VERR_INVALID_PARAMETER);
+
+    return rtDvmDiskWrite(pVol->pVolMgr->pDisk, pVol->offStart + off, pvBuf, cbWrite);
+}
+
+DECLHIDDEN(RTDVMFMTOPS) g_rtDvmFmtBsdLbl = 
+{
+    /* pcszFmt */
+    "BsdLabel",
+    /* pfnProbe */
+    rtDvmFmtBsdLblProbe,
+    /* pfnOpen */
+    rtDvmFmtBsdLblOpen,
+    /* pfnInitialize */
+    rtDvmFmtBsdLblInitialize,
+    /* pfnClose */
+    rtDvmFmtBsdLblClose,
+    /* pfnGetValidVolumes */
+    rtDvmFmtBsdLblGetValidVolumes,
+    /* pfnGetMaxVolumes */
+    rtDvmFmtBsdLblGetMaxVolumes,
+    /* pfnQueryFirstVolume */
+    rtDvmFmtBsdLblQueryFirstVolume,
+    /* pfnQueryNextVolume */
+    rtDvmFmtBsdLblQueryNextVolume,
+    /* pfnVolumeClose */
+    rtDvmFmtBsdLblVolumeClose,
+    /* pfnVolumeGetSize */
+    rtDvmFmtBsdLblVolumeGetSize,
+    /* pfnVolumeQueryName */
+    rtDvmFmtBsdLblVolumeQueryName,
+    /* pfnVolumeGetType */
+    rtDvmFmtBsdLblVolumeGetType,
+    /* pfnVolumeGetFlags */
+    rtDvmFmtBsdLblVolumeGetFlags,
+    /* pfnVolumeRead */
+    rtDvmFmtBsdLblVolumeRead,
+    /* pfnVolumeWrite */
+    rtDvmFmtBsdLblVolumeWrite
+};
+
Index: /trunk/src/VBox/Runtime/include/internal/dvm.h
===================================================================
--- /trunk/src/VBox/Runtime/include/internal/dvm.h	(revision 37269)
+++ /trunk/src/VBox/Runtime/include/internal/dvm.h	(revision 37270)
@@ -227,4 +227,9 @@
 typedef const RTDVMFMTOPS *PCRTDVMFMTOPS;
 
+/** Converts a LBA number to the byte offset. */
+#define RTDVM_LBA2BYTE(lba, disk) ((lba) * (disk)->cbSector)
+/** Converts a Byte offset to the LBA number. */
+#define RTDVM_BYTE2LBA(off, disk) ((off) / (disk)->cbSector)
+
 /**
  * Returns the number of sectors in the disk.
Index: /trunk/src/VBox/Runtime/testcase/tstRTDvm.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTDvm.cpp	(revision 37269)
+++ /trunk/src/VBox/Runtime/testcase/tstRTDvm.cpp	(revision 37270)
@@ -34,16 +34,136 @@
 #include <iprt/dvm.h>
 #include <iprt/file.h>
-
-RTFILE   g_hDisk = NIL_RTFILE;  /**< The disk image. */
-uint64_t g_cbDisk = 0;          /**< Size of the image. */
+#include <iprt/string.h>
+
+/**
+ * Disk structure.
+ */
+typedef struct TSTRTDVMDISK
+{
+    /** Flag whether this disk uses the image file or a volume. */
+    bool            fUseImage;
+    /** Data dependent on the flag. */
+    union
+    {
+        /** File handle of the image. */
+        RTFILE      hImage;
+        /** Handle of the volume. */
+        RTDVMVOLUME hVol;
+    };
+} TSTRTDVMDISK, *PTSTRTDVMDISK;
 
 static int dvmDiskRead(void *pvUser, uint64_t off, void *pvBuf, size_t cbRead)
 {
-    return RTFileReadAt(g_hDisk, off, pvBuf, cbRead, NULL);
+    PTSTRTDVMDISK pDisk = (PTSTRTDVMDISK)pvUser;
+
+    if (pDisk->fUseImage)
+        return RTFileReadAt(pDisk->hImage, off, pvBuf, cbRead, NULL);
+    else
+        return RTDvmVolumeRead(pDisk->hVol, off, pvBuf, cbRead);
 }
 
 static int dvmDiskWrite(void *pvUser, uint64_t off, const void *pvBuf, size_t cbWrite)
 {
-    return RTFileWriteAt(g_hDisk, off, pvBuf, cbWrite, NULL);
+    PTSTRTDVMDISK pDisk = (PTSTRTDVMDISK)pvUser;
+
+    if (pDisk->fUseImage)
+        return RTFileWriteAt(pDisk->hImage, off, pvBuf, cbWrite, NULL);
+    else
+        return RTDvmVolumeWrite(pDisk->hVol, off, pvBuf, cbWrite);
+}
+
+static int tstRTDvmVolume(RTTEST hTest, PTSTRTDVMDISK pDisk, uint64_t cb, unsigned cNesting)
+{
+    char szPrefix[100];
+    int rc = VINF_SUCCESS;
+
+    memset(szPrefix, 0, sizeof(szPrefix));
+
+    if (cNesting < sizeof(szPrefix) - 1)
+    {
+        for (unsigned i = 0; i < cNesting; i++)
+            szPrefix[i] = '\t';
+    }
+
+    RTTestSubF(hTest, "Create DVM");
+    RTDVM hVolMgr;
+    rc = RTDvmCreate(&hVolMgr, dvmDiskRead, dvmDiskWrite, cb, 512, pDisk);
+    if (RT_FAILURE(rc))
+    {
+        RTTestIFailed("RTDvmCreate -> %Rrc", rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+
+    RTTestSubF(hTest, "Open volume map");
+    rc = RTDvmMapOpen(hVolMgr);
+    if (   RT_FAILURE(rc)
+        && rc != VERR_NOT_SUPPORTED)
+    {
+        RTTestIFailed("RTDvmOpen -> %Rrc", rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+    else if (rc == VERR_NOT_SUPPORTED)
+        return VINF_SUCCESS;
+
+    RTTestIPrintf(RTTESTLVL_ALWAYS, "%s Successfully opened map with format: %s.\n", szPrefix, RTDvmMapGetFormat(hVolMgr));
+
+    /* Dump all volumes. */
+    RTTestSubF(hTest, "Dump volumes");
+    uint32_t cVolume = 0;
+    RTDVMVOLUME hVol;
+
+    rc = RTDvmMapQueryFirstVolume(hVolMgr, &hVol);
+
+    while (RT_SUCCESS(rc))
+    {
+        char *pszVolName = NULL;
+        RTDVMVOLTYPE enmVolType = RTDvmVolumeGetType(hVol);
+        uint64_t fVolFlags = RTDvmVolumeGetFlags(hVol);
+
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s Volume %u:\n", szPrefix, cVolume);
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s Volume type  %s\n", szPrefix, RTDvmVolumeTypeGetDescr(enmVolType));
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s Volume size  %llu\n", szPrefix, RTDvmVolumeGetSize(hVol));
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s Volume flags %s %s\n\n", szPrefix,
+                      fVolFlags & DVMVOLUME_FLAGS_BOOTABLE ? "Bootable" : "",
+                      fVolFlags & DVMVOLUME_FLAGS_ACTIVE ? "Active" : "");
+
+        rc = RTDvmVolumeQueryName(hVol, &pszVolName);
+        if (RT_SUCCESS(rc))
+        {
+            RTTestIPrintf(RTTESTLVL_ALWAYS, "%s Volume name %s.\n", szPrefix, pszVolName);
+            RTStrFree(pszVolName);
+        }
+        else if (rc != VERR_NOT_SUPPORTED)
+            RTTestIFailed("RTDvmVolumeQueryName -> %Rrc", rc);
+        else
+            rc = VINF_SUCCESS;
+
+        /*
+         * Query all volumes which might be inside this.
+         * (think of MBR partitions with a bsdlabel inside)
+         */
+        TSTRTDVMDISK Disk;
+        Disk.fUseImage = false;
+        Disk.hVol      = hVol;
+        rc = tstRTDvmVolume(hTest, &Disk, RTDvmVolumeGetSize(hVol), cNesting + 1);
+
+        RTDVMVOLUME hVolNext;
+        rc = RTDvmMapQueryNextVolume(hVolMgr, hVol, &hVolNext);
+        RTDvmVolumeRelease(hVol);
+        hVol = hVolNext;
+        cVolume++;
+    }
+
+    RTTestIPrintf(RTTESTLVL_ALWAYS, "%s Dumped %u volumes\n", szPrefix, cVolume);
+
+    if (   rc == VERR_DVM_MAP_EMPTY
+        || rc == VERR_DVM_MAP_NO_VOLUME)
+        rc = VINF_SUCCESS;
+
+    RTTESTI_CHECK(rc == VINF_SUCCESS);
+
+    RTDvmRelease(hVolMgr);
+
+    return rc;
 }
 
@@ -69,5 +189,7 @@
 
     /* Open image. */
-    rc = RTFileOpen(&g_hDisk, argv[1], RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE);
+    RTFILE hFile;
+    uint64_t cb = 0;
+    rc = RTFileOpen(&hFile, argv[1], RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE);
     if (RT_FAILURE(rc))
     {
@@ -76,7 +198,7 @@
     }
 
-    rc = RTFileGetSize(g_hDisk, &g_cbDisk);
+    rc = RTFileGetSize(hFile, &cb);
     if (   RT_FAILURE(rc)
-        || g_cbDisk % 512 != 0) /* Assume 512 byte sector size. */
+        || cb % 512 != 0) /* Assume 512 byte sector size. */
     {
         RTTestIFailed("RTFileGetSize -> %Rrc", rc);
@@ -84,58 +206,11 @@
     }
 
-    RTTestSubF(hTest, "Create DVM");
-    RTDVM hVolMgr;
-    rc = RTDvmCreate(&hVolMgr, dvmDiskRead, dvmDiskWrite, g_cbDisk, 512, NULL);
-    if (RT_FAILURE(rc))
-    {
-        RTTestIFailed("RTDvmCreate -> %Rrc", rc);
-        return RTTestSummaryAndDestroy(hTest);
-    }
-
-    RTTestSubF(hTest, "Open volume map");
-    rc = RTDvmMapOpen(hVolMgr);
-    if (RT_FAILURE(rc))
-    {
-        RTTestIFailed("RTDvmOpen -> %Rrc", rc);
-        return RTTestSummaryAndDestroy(hTest);
-    }
-
-    RTTestIPrintf(RTTESTLVL_ALWAYS, " Successfully opened map with format: %s.\n", RTDvmMapGetFormat(hVolMgr));
-
-    /* Dump all volumes. */
-    RTTestSubF(hTest, "Dump volumes");
-    uint32_t cVolume = 0;
-    RTDVMVOLUME hVol;
-
-    rc = RTDvmMapQueryFirstVolume(hVolMgr, &hVol);
-
-    while (RT_SUCCESS(rc))
-    {
-        RTDVMVOLTYPE enmVolType = RTDvmVolumeGetType(hVol);
-        uint64_t fVolFlags = RTDvmVolumeGetFlags(hVol);
-
-        RTTestIPrintf(RTTESTLVL_ALWAYS, " Volume %u:\n", cVolume);
-        RTTestIPrintf(RTTESTLVL_ALWAYS, " Volume type  %s.\n", RTDvmVolumeTypeGetDescr(enmVolType));
-        RTTestIPrintf(RTTESTLVL_ALWAYS, " Volume size  %llu.\n", RTDvmVolumeGetSize(hVol));
-        RTTestIPrintf(RTTESTLVL_ALWAYS, " Volume flags %s %s.\n\n", 
-                      fVolFlags & DVMVOLUME_FLAGS_BOOTABLE ? "Bootable" : "",
-                      fVolFlags & DVMVOLUME_FLAGS_ACTIVE ? "Active" : "");
-
-        RTDVMVOLUME hVolNext;
-        rc = RTDvmMapQueryNextVolume(hVolMgr, hVol, &hVolNext);
-        RTDvmVolumeRelease(hVol);
-        hVol = hVolNext;
-        cVolume++;
-    }
-
-    RTTestIPrintf(RTTESTLVL_ALWAYS, " Dumped %u volumes\n", cVolume);
-
-    if (   rc == VERR_DVM_MAP_EMPTY
-        || rc == VERR_DVM_MAP_NO_VOLUME)
-        rc = VINF_SUCCESS;
+    TSTRTDVMDISK Disk;
+
+    Disk.fUseImage = true;
+    Disk.hImage    = hFile;
+    rc = tstRTDvmVolume(hTest, &Disk, cb, 0);
 
     RTTESTI_CHECK(rc == VINF_SUCCESS);
-
-    RTDvmRelease(hVolMgr);
 
     /*
