tstRTDvm.cpp revision 2a0a20dee7f474c26cc8f6f9d7aa12c345c2b73b
/* $Id$ */
/** @file
* IPRT Testcase - IPRT Disk Volume Management (DVM)
*/
/*
* Copyright (C) 2009 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/dvm.h>
#include <iprt/err.h>
#include <iprt/test.h>
#include <iprt/file.h>
#include <iprt/string.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* 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)
{
PTSTRTDVMDISK pDisk = (PTSTRTDVMDISK)pvUser;
if (pDisk->fUseImage)
return RTFileReadAt(pDisk->hImage, off, pvBuf, cbRead, NULL);
return RTDvmVolumeRead(pDisk->hVol, off, pvBuf, cbRead);
}
static int dvmDiskWrite(void *pvUser, uint64_t off, const void *pvBuf, size_t cbWrite)
{
PTSTRTDVMDISK pDisk = (PTSTRTDVMDISK)pvUser;
if (pDisk->fUseImage)
return RTFileWriteAt(pDisk->hImage, off, pvBuf, cbWrite, NULL);
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;
RT_ZERO(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, 0, 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);
}
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;
}
int main(int argc, char **argv)
{
/*
* Initialize IPRT and create the test.
*/
RTTEST hTest;
int rc = RTTestInitAndCreate("tstRTDvm", &hTest);
if (rc)
return rc;
RTTestBanner(hTest);
/*
* If no args, display usage.
*/
if (argc < 2)
{
RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "Syntax: %s <image>\n", argv[0]);
return RTTestSkipAndDestroy(hTest, "Missing required arguments\n");
}
/* Open image. */
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))
{
RTTestIFailed("RTFileOpen -> %Rrc", rc);
return RTTestSummaryAndDestroy(hTest);
}
rc = RTFileGetSize(hFile, &cb);
if ( RT_FAILURE(rc)
|| cb % 512 != 0) /* Assume 512 byte sector size. */
{
RTTestIFailed("RTFileGetSize -> %Rrc", rc);
return RTTestSummaryAndDestroy(hTest);
}
TSTRTDVMDISK Disk;
Disk.fUseImage = true;
Disk.hImage = hFile;
rc = tstRTDvmVolume(hTest, &Disk, cb, 0);
RTTESTI_CHECK(rc == VINF_SUCCESS);
/*
* Summary
*/
return RTTestSummaryAndDestroy(hTest);
}