956a0e3c076406b83d635174a201fd8761ee5133vboxsync * IPRT Disk Volume Management API (DVM) - generic code.
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2011-2012 Oracle Corporation
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * available from http://www.virtualbox.org. This file is free software;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * you can redistribute it and/or modify it under the terms of the GNU
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * General Public License (GPL) as published by the Free Software
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * The contents of this file may alternatively be used under the terms
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * of the Common Development and Distribution License Version 1.0
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * VirtualBox OSE distribution, in which case the provisions of the
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * CDDL are applicable instead of those of the GPL.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * You may elect to license modified versions of this file under the
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * terms and conditions of either the GPL or the CDDL or both.
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync/*******************************************************************************
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync* Header Files *
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync*******************************************************************************/
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/*******************************************************************************
956a0e3c076406b83d635174a201fd8761ee5133vboxsync* Structures and Typedefs *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync*******************************************************************************/
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * The internal volume manager structure.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** The DVM magic (RTDVM_MAGIC). */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** The disk descriptor. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Pointer to the backend operations table after a successful probe. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** The format specific volume manager data. */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /** Flags passed on manager creation. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Reference counter. */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /** List of recognised volumes (RTDVMVOLUMEINTERNAL). */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/** Pointer to an internal volume manager. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * The internal volume structure.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** The DVM volume magic (RTDVMVOLUME_MAGIC). */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /** Node for the volume list. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Pointer to the owning volume manager. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Format specific volume data. */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /** Set block status.callback */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /** Opaque user data. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Reference counter. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/** Pointer to an internal volume. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/*******************************************************************************
956a0e3c076406b83d635174a201fd8761ee5133vboxsync* Global variables *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync*******************************************************************************/
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Supported volume formats.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Descriptions of the volume types.
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync * This is indexed by RTDVMVOLTYPE.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync "Linux swap",
956a0e3c076406b83d635174a201fd8761ee5133vboxsync "Linux native",
956a0e3c076406b83d635174a201fd8761ee5133vboxsync "Linux LVM",
956a0e3c076406b83d635174a201fd8761ee5133vboxsync "Linux SoftRaid",
956a0e3c076406b83d635174a201fd8761ee5133vboxsync "Mac OS X HFS or HFS+",
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync * Creates a new volume.
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync * @returns IPRT status code.
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync * @param pThis The DVM map instance.
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync * @param hVolFmt The format specific volume handle.
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync * @param phVol Where to store the generic volume handle on success.
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsyncstatic int rtDvmVolumeCreate(PRTDVMINTERNAL pThis, RTDVMVOLUMEFMT hVolFmt,
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync pVol = (PRTDVMVOLUMEINTERNAL)RTMemAllocZ(sizeof(RTDVMVOLUMEINTERNAL));
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync * Destroys a volume handle.
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync * @param pThis The volume to destroy.
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsyncstatic void rtDvmVolumeDestroy(PRTDVMVOLUMEINTERNAL pThis)
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /* Close the volume. */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync pVolMgr->pDvmFmtOps->pfnVolumeClose(pThis->hVolFmt);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /* Release the reference of the volume manager. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(int) RTDvmCreate(PRTDVM phVolMgr, PFNDVMREAD pfnRead,
956a0e3c076406b83d635174a201fd8761ee5133vboxsync pThis = (PRTDVMINTERNAL)RTMemAllocZ(sizeof(RTDVMINTERNAL));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Destroys a volume manager handle.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param pThis The volume manager to destroy.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Let the backend do it's own cleanup first. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint32_t uScoreMax = RTDVM_MATCH_SCORE_UNSUPPORTED;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync rc = pDvmFmtOps->pfnProbe(&pThis->DvmDisk, &uScore);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Open the format. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync rc = pDvmFmtOpsMatch->pfnOpen(&pThis->DvmDisk, &pThis->hVolMgrFmt);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync cVols = pThis->pDvmFmtOps->pfnGetValidVolumes(pThis->hVolMgrFmt);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /* Construct volume list. */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync rc = pThis->pDvmFmtOps->pfnQueryFirstVolume(pThis->hVolMgrFmt, &hVolFmt);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync RTListAppend(&pThis->VolumeList, &pVol->VolumeNode);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync rc = pThis->pDvmFmtOps->pfnQueryNextVolume(pThis->hVolMgrFmt, pVol->hVolFmt, &hVolFmt);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync RTListAppend(&pThis->VolumeList, &pVol->VolumeNode);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /* Remove all entries. */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync RTListForEachSafe(&pThis->VolumeList, pIt, pItNext, RTDVMVOLUMEINTERNAL, VolumeNode)
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(int) RTDvmMapInitialize(RTDVM hVolMgr, const char *pszFmt)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->hVolMgrFmt == NIL_RTDVMFMT, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync for (unsigned i = 0; i < RT_ELEMENTS(g_aDvmFmts); i++)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync rc = pDvmFmtOps->pfnInitialize(&pThis->DvmDisk, &pThis->hVolMgrFmt);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(const char *) RTDvmMapGetFormat(RTDVM hVolMgr)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, NULL);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, NULL);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(uint32_t) RTDvmMapGetValidVolumes(RTDVM hVolMgr)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pDvmFmtOps->pfnGetValidVolumes(pThis->hVolMgrFmt);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(uint32_t) RTDvmMapGetMaxVolumes(RTDVM hVolMgr)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, UINT32_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, UINT32_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pDvmFmtOps->pfnGetMaxVolumes(pThis->hVolMgrFmt);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsyncRTDECL(int) RTDvmMapQueryFirstVolume(RTDVM hVolMgr, PRTDVMVOLUME phVol)
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync PRTDVMVOLUMEINTERNAL pVol = RTListGetFirst(&pThis->VolumeList, RTDVMVOLUMEINTERNAL, VolumeNode);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsyncRTDECL(int) RTDvmMapQueryNextVolume(RTDVM hVolMgr, RTDVMVOLUME hVol, PRTDVMVOLUME phVolNext)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync AssertReturn(pVol->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync PRTDVMVOLUMEINTERNAL pVolNext = RTListGetNext(&pThis->VolumeList, pVol,
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsyncRTDECL(int) RTDvmMapQueryBlockStatus(RTDVM hVolMgr, uint64_t off, uint64_t cb,
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync AssertPtrReturn(pfAllocated, VERR_INVALID_POINTER);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVM_MAGIC, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->hVolMgrFmt != NIL_RTDVMFMT, VERR_INVALID_HANDLE);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync AssertReturn(off + cb <= pThis->DvmDisk.cbDisk * pThis->DvmDisk.cbSector,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /* Check whether the range is inuse by the volume manager metadata first. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = pThis->pDvmFmtOps->pfnQueryRangeUse(pThis->hVolMgrFmt, off, cb, pfAllocated);
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync while ( cb > 0
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync * Search through all volumes. It is not possible to
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync * get all start sectors and sizes of all volumes here
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync * because volumes can be scattered around the disk for certain formats.
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync * Linux LVM is one example, extents of logical volumes don't need to be
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync * contigous on the medium.
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync RTListForEach(&pThis->VolumeList, pVol, RTDVMVOLUMEINTERNAL, VolumeNode)
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync bool fIntersect = pThis->pDvmFmtOps->pfnVolumeIsRangeIntersecting(pVol->hVolFmt, off,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = pVol->pfnQueryBlockStatus(pVol->pvUser, offVol, cbIntersect,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync else if (!(pThis->fFlags & DVM_FLAGS_NO_STATUS_CALLBACK_MARK_AS_UNUSED))
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /* else, flag is set, continue. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync if (pThis->fFlags & DVM_FLAGS_UNUSED_SPACE_MARK_AS_USED)
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(uint32_t) RTDvmVolumeRetain(RTDVMVOLUME hVol)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync AssertMsg(cRefs >= 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(uint32_t) RTDvmVolumeRelease(RTDVMVOLUME hVol)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT32_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync /* Release the volume manager. */
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsyncRTDECL(void) RTDvmVolumeSetQueryBlockStatusCallback(RTDVMVOLUME hVol,
2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73bvboxsync AssertReturnVoid(pThis->u32Magic == RTDVMVOLUME_MAGIC);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(uint64_t) RTDvmVolumeGetSize(RTDVMVOLUME hVol)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, 0);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetSize(pThis->hVolFmt);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(int) RTDvmVolumeQueryName(RTDVMVOLUME hVol, char **ppszVolName)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pVolMgr->pDvmFmtOps->pfnVolumeQueryName(pThis->hVolFmt, ppszVolName);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(RTDVMVOLTYPE) RTDvmVolumeGetType(RTDVMVOLUME hVol)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, RTDVMVOLTYPE_INVALID);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetType(pThis->hVolFmt);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(uint64_t) RTDvmVolumeGetFlags(RTDVMVOLUME hVol)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, UINT64_MAX);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pVolMgr->pDvmFmtOps->pfnVolumeGetFlags(pThis->hVolFmt);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(int) RTDvmVolumeRead(RTDVMVOLUME hVol, uint64_t off, void *pvBuf, size_t cbRead)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pVolMgr->pDvmFmtOps->pfnVolumeRead(pThis->hVolFmt, off, pvBuf, cbRead);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(int) RTDvmVolumeWrite(RTDVMVOLUME hVol, uint64_t off, const void *pvBuf, size_t cbWrite)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertReturn(pThis->u32Magic == RTDVMVOLUME_MAGIC, VERR_INVALID_HANDLE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return pThis->pVolMgr->pDvmFmtOps->pfnVolumeWrite(pThis->hVolFmt, off, pvBuf, cbWrite);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRTDECL(const char *) RTDvmVolumeTypeGetDescr(RTDVMVOLTYPE enmVolType)