summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/dvm/dvm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/dvm/dvm.cpp')
-rw-r--r--src/VBox/Runtime/common/dvm/dvm.cpp481
1 files changed, 481 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/dvm/dvm.cpp b/src/VBox/Runtime/common/dvm/dvm.cpp
new file mode 100644
index 000000000..eb9fe7021
--- /dev/null
+++ b/src/VBox/Runtime/common/dvm/dvm.cpp
@@ -0,0 +1,481 @@
+/* $Id: dvm.cpp 37270 2011-05-30 21:25:42Z vboxsync $ */
+/** @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.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#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_rtDvmFmtMbr;
+extern RTDVMFMTOPS g_rtDvmFmtGpt;
+extern RTDVMFMTOPS g_rtDvmFmtBsdLbl;
+
+/**
+ * Supported volume formats.
+ */
+static PCRTDVMFMTOPS g_aDvmFmts[] =
+{
+ &g_rtDvmFmtMbr,
+ &g_rtDvmFmtGpt,
+ &g_rtDvmFmtBsdLbl
+};
+
+/**
+ * Descriptions of the volume types.
+ *
+ * This is indexed by RTDVMVOLTYPE.
+ */
+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_SUPPORTED;
+ }
+
+ 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_END, NULL);
+
+ return g_apcszDvmVolTypes[enmVolType];
+}