www.pudn.com > vdksrc.zip > VDiskPlain.cpp
/*
VDiskPlain.cpp
Plain disk class
Copyright (c) 2003 Ken Kato
*/
#include "vdkbase.h"
#include "vdkutil.h"
#include "cowdisk.h"
#include "VDiskPlain.h"
#include "VDiskExtRaw.h"
#include "VDiskUtil.h"
#include "VDiskFile.h"
//
// Constructor -- set default members
//
VDiskPlain::VDiskPlain()
{
m_nVMwareVer = 2;
m_nHardwareVer = COWD_HARDWARE_VMWARE2;
}
//
// Destructor
//
VDiskPlain::~VDiskPlain()
{
}
//
// Initialize instance from a VMware 2.x plain disk descriptor file
//
VDKSTAT VDiskPlain::Initialize(PCHAR pPath)
{
VDiskFile file;
CHAR buf[MAX_PATH + 40];
CHAR path[MAX_PATH];
PCHAR current;
VDKSTAT ret;
PVOID cbparams[2];
//
// parameter check
//
if (!pPath || !*pPath) {
return VDK_PARAM;
}
//
// store path
//
if ((ret = StorePath(pPath)) != VDK_OK) {
return ret;
}
//
// open file
//
if ((ret = file.Open(pPath)) != VDK_OK) {
return ret;
}
//
// initialize members
//
ClrFlag(VDISK_FLAG_CHILD);
cbparams[0] = pPath;
while ((ret = file.ReadText(buf, sizeof(buf), NULL)) == VDK_OK) {
//
// replace tabs with blanks
//
current = buf;
while (*current) {
if (*current == '\t' || *current == '\n') {
*current = ' ';
}
current++;
}
//
// remove trailing blanks
//
while (current > buf && *(--current) == ' ') {
*current = '\0';
}
//
// skip leading blanks
//
current = buf;
while (*current == ' ') {
current++;
}
//
// blank line?
//
if (!*current) {
continue;
}
cbparams[1] = current;
//
// start parsing
//
if (!VdkCmpNoCaseN(current, "ACCESS ", 7)) {
VDiskExtRaw *ext;
PCHAR top, tail;
ULONG capacity;
ULONG offset;
CHAR delim;
HANDLE hFile;
//
// search path field
//
top = current + 7;
while (*top == ' ') {
top++;
}
if (*top == '\"') {
delim = '\"';
top++;
}
else {
delim = ' ';
}
tail = top;
while (*tail && *tail != delim) {
tail++;
}
if (!*tail || tail - top >= MAX_PATH) {
if (!VDiskCallBack(VDISK_CB_DESC_BADENTRY, cbparams)) {
return VDK_CANCEL;
}
SetFlag(VDISK_FLAG_DIRTY);
continue;
}
if ((isalpha(*top) && *(top + 1) == ':') ||
*top == PATH_SEPARATOR_CHAR ||
*top == ALT_SEPARATOR_CHAR) {
SetFlag(VDISK_FLAG_ABSPATH);
}
else {
ClrFlag(VDISK_FLAG_ABSPATH);
}
VdkCopyMem(path, top, tail - top);
path[tail - top] = '\0';
//
// search offset field
//
top = tail + 1;
while (*top == ' ') {
top++;
}
if (isdigit(*top)) {
offset = atol(top);
}
else {
offset = VDiskCallBack(
VDISK_CB_DESC_OFFSET, cbparams);
if (offset == (ULONG)-1) {
return VDK_DATA;
}
SetFlag(VDISK_FLAG_DIRTY);
}
//
// search capacity field
//
while (isdigit(*top)) {
top++;
}
while (*top == ' ') {
top++;
}
capacity = atol(top);
if (!capacity) {
capacity = VDiskCallBack(
VDISK_CB_DESC_CAPACITY, cbparams);
if (!capacity) {
return VDK_DATA;
}
SetFlag(VDISK_FLAG_DIRTY);
}
//
// create an extent object
//
ext = new VDiskExtRaw;
if (ext == NULL) {
return VdkLastError();
}
ret = AddExtent(ext);
if (ret != VDK_OK) {
delete ext;
return ret;
}
ret = VDiskSearchFile(&hFile, path, m_pPath);
if (ret != VDK_OK) {
return ret;
}
ret = ext->SetPath(path);
if (ret != VDK_OK) {
return ret;
}
ret = ext->Load(hFile);
VdkCloseFile(hFile);
if (ret != VDK_OK) {
return ret;
}
ext->SetCapacity(capacity);
ext->SetStartOffset(offset);
}
else if (!VdkCmpNoCaseN(current, "CYLINDERS ", 10)) {
m_nCylinders = atol(current + 10);
if (!m_nCylinders) {
m_nCylinders = VDiskCallBack(
VDISK_CB_DESC_GEOMETRY, cbparams);
if (!m_nCylinders) {
return VDK_DATA;
}
SetFlag(VDISK_FLAG_DIRTY);
}
}
else if (!VdkCmpNoCaseN(current, "HEADS ", 6)) {
m_nTracks = atol(current + 6);
if (!m_nTracks) {
m_nTracks = VDiskCallBack(
VDISK_CB_DESC_GEOMETRY, cbparams);
if (!m_nTracks) {
return VDK_DATA;
}
SetFlag(VDISK_FLAG_DIRTY);
}
}
else if (!VdkCmpNoCaseN(current, "SECTORS ", 8)) {
m_nSectors = atol(current + 8);
if (!m_nSectors) {
m_nSectors = VDiskCallBack(
VDISK_CB_DESC_GEOMETRY, cbparams);
if (!m_nSectors) {
return VDK_DATA;
}
SetFlag(VDISK_FLAG_DIRTY);
}
}
else if (!VdkCmpNoCaseN(current, "DRIVETYPE ", 10)) {
PCHAR p = current + 10;
while (*p == ' ') {
p++;
}
if (!VdkCmpNoCase(p, "scsi")) {
m_nController = VDISK_CONTROLLER_SCSI;
}
else if (!VdkCmpNoCase(p, "ide")) {
m_nController = VDISK_CONTROLLER_IDE;
}
else {
m_nController = VDiskCallBack(
VDISK_CB_CONTROLLER, cbparams);
if (m_nController != VDISK_CONTROLLER_SCSI &&
m_nController != VDISK_CONTROLLER_IDE) {
return VDK_CANCEL;
}
SetFlag(VDISK_FLAG_DIRTY);
}
}
else if (!VdkCmpNoCaseN(current, "#vm|TOOLSVERSION ", 17)) {
m_nVMwareVer = 3;
m_nToolsFlag = atol(current + 17);
}
else if (!VdkCmpNoCaseN(current, "#vm|VERSION ", 12)) {
m_nVMwareVer = 3;
m_nHardwareVer = atol(current + 12);
if (m_nHardwareVer != COWD_HARDWARE_VMWARE2 &&
m_nHardwareVer != COWD_HARDWARE_VMWARE3 &&
m_nHardwareVer != COWD_HARDWARE_VMWARE4) {
m_nHardwareVer = VDiskCallBack(
VDISK_CB_HARDWAREVER, cbparams);
if (m_nHardwareVer != COWD_HARDWARE_VMWARE2 &&
m_nHardwareVer != COWD_HARDWARE_VMWARE3 &&
m_nHardwareVer != COWD_HARDWARE_VMWARE4) {
return VDK_CANCEL;
}
SetFlag(VDISK_FLAG_DIRTY);
}
}
else if (*current != '#') {
if (!VDiskCallBack(VDISK_CB_DESC_BADENTRY, cbparams)) {
return VDK_CANCEL;
}
SetFlag(VDISK_FLAG_DIRTY);
}
}
file.Close();
if (ret == VDK_EOF) {
ret = Check();
}
return ret;
}
//
// Initialize as a child disk
//
VDKSTAT VDiskPlain::InitChild(
ULONG flags,
PCHAR pPath,
ULONG version,
VDisk *parent)
{
UNREFERENCED_PARAMETER(flags);
UNREFERENCED_PARAMETER(pPath);
UNREFERENCED_PARAMETER(version);
UNREFERENCED_PARAMETER(parent);
//
// Plain Disk cannot be a child
//
return VDK_FUNCTION;
}
//
// Check paramters
//
VDKSTAT VDiskPlain::Check()
{
CHAR path[MAX_PATH];
PVOID cbparams[3];
ULONG idx;
VDKSTAT ret;
FullPath(path);
//
// At least one extent must be present
//
if (!m_nExtents) {
cbparams[0] = path;
VDiskCallBack(VDISK_CB_EMPTY_IMAGE, cbparams);
return VDK_DATA;
}
//
// Check extent offset
//
m_nCapacity = 0;
for (idx = 0; idx < m_nExtents; idx++) {
VDiskExtRaw *ext = (VDiskExtRaw *)m_ppExtents[idx];
if (ext->GetStartOffset() != m_nCapacity) {
cbparams[0] = ext->GetFullPath();
cbparams[1] = (PVOID)ext->GetStartOffset();
cbparams[2] = (PVOID)m_nCapacity;
//
// file range conflict or there is a hole
//
if (!VDiskCallBack(VDISK_CB_EXT_OFFSET, cbparams)) {
return VDK_CANCEL;
}
ext->SetStartOffset(m_nCapacity);
SetFlag(VDISK_FLAG_DIRTY);
}
if ((ret = ext->Check()) != VDK_OK) {
return ret;
}
if (ext->IsModified()) {
SetFlag(VDISK_FLAG_DIRTY);
}
m_nCapacity += ext->GetCapacity();
}
cbparams[0] = path;
//
// Check geometry
//
/*
if (m_nCylinders * m_nTracks * m_nSectors != m_nCapacity) {
cbparams[1] = (PVOID)m_nCapacity;
cbparams[2] = (PVOID)total_size;
if (!VDiskCallBack(VDISK_CB_EXT_CAPACITY, cbparams)) {
return VDK_DATA;
}
m_nCapacity = total_size;
SetGeometry();
SetFlag(VDISK_FLAG_DIRTY);
for (idx = 0; idx < m_nExtents; idx++) {
if (total_size < m_ppExtents[idx]->GetCapacity()) {
m_ppExtents[idx]->SetCapacity(total_size);
total_size = 0;
}
else {
total_size -= m_ppExtents[idx]->GetCapacity();
}
}
}
*/
//
// Any bad parameter?
//
if (m_nFlags & VDISK_FLAG_DIRTY) {
if (VDiskCallBack(VDISK_CB_CONFIRM_FIX, cbparams)) {
ret = WriteDescriptor(FALSE, FALSE);
if (ret != VDK_OK) {
return ret;
}
for (idx = 0; idx < m_nExtents; idx++) {
ret = m_ppExtents[idx]->Update();
if (ret != VDK_OK) {
return ret;
}
}
}
ClrFlag(VDISK_FLAG_DIRTY);
}
return VDK_OK;
}
//
// create plain disk descriptor file and extent files
//
VDKSTAT VDiskPlain::Create(ULONG flags)
{
ULONG idx;
VDKSTAT ret;
if (!m_nExtents || !m_ppExtents || !m_ppExtents[0]) {
return VDK_FUNCTION;
}
//
// create each extent file
//
for (idx = 0; idx < m_nExtents; idx++) {
ret = m_ppExtents[idx]->Create(flags);
if (ret != VDK_OK) {
return ret;
}
}
//
// create the description file
//
ret = WriteDescriptor(TRUE, (flags & VDISK_CREATE_FORCE));
return ret;
}
//
// Write plain disk descriptor file
//
VDKSTAT VDiskPlain::WriteDescriptor(BOOL create, BOOL force)
{
CHAR buf[MAX_PATH + 30];
ULONG idx;
ULONG path_len;
HANDLE hFile = INVALID_HANDLE_VALUE;
VDKSTAT ret = VDK_OK;
//
// create/open the description file
//
FullPath(buf);
if (create) {
ret = VdkCreateFile(&hFile, buf, force);
}
else {
ret = VdkOpenFile(&hFile, buf, strlen(buf), FALSE);
}
if (ret != VDK_OK) {
return ret;
}
//
// create header entries
//
buf[0] = '\0';
if (m_nVMwareVer == 3) {
//
// additional entry for VMware 3.x
//
sprintf(buf,
"#vm|TOOLSVERSION %lu\n"
"#vm|VERSION %lu\n",
m_nToolsFlag, m_nHardwareVer);
}
sprintf(buf + strlen(buf),
"DRIVETYPE %s\n"
"CYLINDERS %6lu\n"
"HEADS %6lu\n"
"SECTORS %6lu\n",
m_nController == VDISK_CONTROLLER_IDE ? "ide" : "scsi",
m_nCylinders, m_nTracks, m_nSectors);
ret = VdkWriteFileAt(hFile, -1, buf, strlen(buf), NULL);
if (ret != VDK_OK) {
goto cleanup;
}
//
// create each extent entry
//
path_len = strlen(m_pPath);
for (idx = 0; idx < m_nExtents; idx++) {
VDiskExtRaw *ext;
PCHAR path;
ext = (VDiskExtRaw *)m_ppExtents[idx];
path = ext->GetFullPath();
if (!(m_nFlags & VDISK_FLAG_ABSPATH) &&
!VdkCmpNoCaseN(m_pPath, path, path_len)) {
path = ext->GetFileName();
}
sprintf(buf, "ACCESS \"%s\" %lu %lu\n",
path, ext->GetStartOffset(), ext->GetCapacity());
ret = VdkWriteFileAt(hFile, -1, buf, strlen(buf), NULL);
if (ret != VDK_OK) {
goto cleanup;
}
}
cleanup:
if (hFile != INVALID_HANDLE_VALUE) {
VdkCloseFile(hFile);
}
return ret;
}
//
// Create a new extent object for this instance
//
VDiskExt *VDiskPlain::NewExtent()
{
return new VDiskExtRaw;
}
//
// Get path for each extent files
//
void VDiskPlain::GetExtentPath(
PCHAR pPath, ULONG nSeq)
{
sprintf(pPath, "%s" PATH_SEPARATOR_STR "%s%lu.dat",
m_pPath, m_pBody, nSeq + 1);
}
//
// Set default geometry values
//
void VDiskPlain::SetGeometry()
{
if (m_nController == VDISK_CONTROLLER_IDE) {
m_nTracks = COWD1_TRACKS_IDE_PLAIN;
m_nSectors = COWD1_SECTORS_IDE_PLAIN;
}
else {
if (m_nCapacity <=
COWD_SECTORS_SCSI_1023M * COWD_TRACKS_SCSI_1023M * 1023) {
m_nSectors = COWD_SECTORS_SCSI_1023M;
m_nTracks = COWD_TRACKS_SCSI_1023M;
}
else if (m_nCapacity <=
COWD_SECTORS_SCSI_2046M * COWD_TRACKS_SCSI_2046M * 1023) {
m_nSectors = COWD_SECTORS_SCSI_2046M;
m_nTracks = COWD_TRACKS_SCSI_2046M;
}
else {
m_nSectors = COWD_SECTORS_SCSI_LARGE;
m_nTracks = COWD_TRACKS_SCSI_LARGE;
}
}
m_nCylinders = m_nCapacity / (m_nSectors * m_nTracks);
}
//
// Returns default extent size
//
ULONG VDiskPlain::DefaultExtSize()
{
ULONG ext_size = COWD1_MAX_EXTENT_PLAIN;
if (m_nCapacity > ext_size) {
//
// In VMware 2.x plain disks, all extents are the same size
//
ULONG extents = (m_nCapacity + ext_size - 1) / ext_size;
ext_size = (m_nCapacity + extents - 1) / extents;
}
return ext_size;
}