www.pudn.com > vdksrc.zip > VDiskExtCowd.cpp


/*
	VDiskExtCowd.cpp

	COWDisk extent class
	Copyright (c) 2003 Ken Kato
*/

#include "vdkbase.h"
#include "vdkutil.h"

#include "cowdisk.h"

#include "VDisk.h"
#include "VDiskExtCowd.h"
#include "VDiskUtil.h"

//
//	Constructor
//
VDiskExtCowd::VDiskExtCowd()
{
	VdkZeroMem(&m_Sec0, sizeof(COWD_SECTOR_0));
	VdkZeroMem(&m_Sec2, sizeof(COWD_SECTOR_2));
	VdkZeroMem(&m_Sec3, sizeof(COWD_SECTOR_3));
}

//
//	Destructor
//
VDiskExtCowd::~VDiskExtCowd()
{
}

//
//	Load and obtain parameters from a cowdisk file
//
VDKSTAT VDiskExtCowd::Load(HANDLE hFile)
{
	COWD_HEADER	cowd;
	VDKSTAT		ret;

	//
	//	Get file attributes
	//
	m_nFileAttr = VdkGetAttribute(m_pFullPath);

	if (m_nFileAttr == (ULONG)INVALID_FILE_ATTRIBUTES) {
		m_nFileAttr = 0;
	}

	//
	//	Get actual file size
	//
	ret = VdkGetFileSize(hFile, &m_nFileSize);

	if (ret != VDK_OK) {
		return ret;
	}

	//
	//	read COWD header
	//
	ret = VdkReadFileAt(hFile, 0, &cowd, sizeof(COWD_HEADER), NULL);

	if (ret != VDK_OK) {
		return ret;
	}

	//
	//	Store header parameters
	//
	VdkCopyMem(&m_Sec0, &cowd.sec0, sizeof(COWD_SECTOR_0));
	VdkCopyMem(&m_Sec2, &cowd.sec2, sizeof(COWD_SECTOR_2));
	VdkCopyMem(&m_Sec3, &cowd.sec3, sizeof(COWD_SECTOR_3));

	return VDK_OK;
}

//
//	Check parameter consistency
//
VDKSTAT VDiskExtCowd::Check()
{
	ULONG ultmp;
	PVOID cbparams[3];

	cbparams[0] = m_pFullPath;

	//
	//	Signature
	//
	if (m_Sec0.Signature != COWD_SIGNATURE) {

		cbparams[1] = (PVOID)m_Sec0.Signature;

		if (!VDiskCallBack(VDISK_CB_SIGNATURE, cbparams)) {
			return VDK_CANCEL;
		}
	
		m_Sec0.Signature =  COWD_SIGNATURE;
		SetModify();
	}

	//
	//	File version
	//
	if (m_Sec0.Version != COWD_FILEVER_VMWARE2 &&
		m_Sec0.Version != COWD_FILEVER_VMWARE3) {

		cbparams[1] = (PVOID)m_Sec0.Version;

		m_Sec0.Version = VDiskCallBack(
			VDISK_CB_COWD_FILEVER, cbparams);

		if (m_Sec0.Version != COWD_FILEVER_VMWARE2 &&
			m_Sec0.Version != COWD_FILEVER_VMWARE3) {
			return VDK_CANCEL;
		}

		SetModify();
	}

	//
	//	geometries
	//
	if (COWD_IS_ROOT(m_Sec0.Flags)) {

		if (m_Sec0.u.Geometry.Cylinders *
			m_Sec0.u.Geometry.Tracks *
			m_Sec0.u.Geometry.Sectors !=
			m_Sec0.Capacity ||
			!m_Sec0.Capacity) {

			cbparams[1] = &m_Sec0;

			VDiskCallBack(
				VDIDK_CB_COWD_FILEGEOM, cbparams);

			if (m_Sec0.u.Geometry.Cylinders *
				m_Sec0.u.Geometry.Tracks *
				m_Sec0.u.Geometry.Sectors !=
				m_Sec0.Capacity ||
				!m_Sec0.Capacity) {
				return VDK_DATA;
			}

			SetModify();
		}

		if (m_Sec0.Version == COWD_FILEVER_VMWARE3) {
			if (m_Sec3.Cylinders *
				m_Sec3.Tracks *
				m_Sec3.Sectors	!=
				m_Sec3.DiskCapacity ||
				!m_Sec3.DiskCapacity) {

				cbparams[1] = &m_Sec3;

				VDiskCallBack(
					VDISK_CB_COWD_DISKGEOM, cbparams);

				if (m_Sec3.Cylinders *
					m_Sec3.Tracks *
					m_Sec3.Sectors	!=
					m_Sec3.DiskCapacity ||
					!m_Sec3.DiskCapacity) {

					return VDK_DATA;
				}

				SetModify();
			}
		}
	}
	else {

		//	Parent path

		if (!m_Sec0.u.ParentPath[0] ||
			strlen(m_Sec0.u.ParentPath) > MAX_PATH) {

			m_Sec0.u.ParentPath[MAX_PATH] = '\0';
			cbparams[1] = m_Sec0.u.ParentPath;

			if (!VDiskCallBack(VDISK_CB_COWD_PARENT, cbparams) ||
				!m_Sec0.u.ParentPath[0] ||
				strlen(m_Sec0.u.ParentPath) > MAX_PATH) {
				return VDK_DATA;
			}

			SetModify();
		}
	}

	//
	//	Map size
	//
	ultmp = m_Sec0.Granularity * COWD_SECONDARY_MAP_SIZE;
	ultmp = (m_Sec0.Capacity + ultmp - 1) / ultmp;

	if (ultmp != m_Sec0.PrimaryMapSize) {

		cbparams[1] = (PVOID)m_Sec0.PrimaryMapSize;
		cbparams[2] = (PVOID)ultmp;

		if (!VDiskCallBack(VDISK_CB_COWD_MAPSIZE, cbparams)) {
			return VDK_DATA;
		}


		m_Sec0.PrimaryMapSize = ultmp;
		SetModify();
	}

	//
	//	File size
	//
	if ((INT64)m_Sec0.EndOfFile << VDK_BYTE_SHIFT_TO_SECTOR != m_nFileSize) {

		cbparams[1] = (PVOID)m_Sec0.EndOfFile;
		cbparams[2] = (PVOID)(m_nFileSize >> VDK_BYTE_SHIFT_TO_SECTOR);

		if (!VDiskCallBack(VDISK_CB_COWD_ENDOFFILE, cbparams)) {
			return VDK_DATA;
		}


		m_Sec0.EndOfFile = (ULONG)(m_nFileSize >> VDK_BYTE_SHIFT_TO_SECTOR);
		SetModify();
	}

	//
	//	Timestamp
	//
	if (m_Sec2.TimeStamp !=
		m_Sec3.TimeStamp) {

		cbparams[1] = (PVOID)m_Sec2.TimeStamp;
		cbparams[2] = (PVOID)m_Sec3.TimeStamp;

		if (!VDiskCallBack(VDISK_CB_COWD_TIMESTAMP, cbparams)) {
			return VDK_CANCEL;
		}


		m_Sec2.TimeStamp = m_Sec3.TimeStamp;
		SetModify();
	}

	//
	//	Controller type
	//
	if (m_Sec3.Controller != COWD_CONTROLLER_IDE &&
		m_Sec3.Controller != COWD_CONTROLLER_SCSI) {

		cbparams[1] = &(m_Sec3.Controller);

		ultmp = VDiskCallBack(VDISK_CB_CONTROLLER, cbparams);

		if (ultmp == VDISK_CONTROLLER_IDE) {
			m_Sec3.Controller = COWD_CONTROLLER_IDE;
		}
		else if (ultmp == VDISK_CONTROLLER_SCSI) {
			m_Sec3.Controller = COWD_CONTROLLER_SCSI;
		}
		else {
			return VDK_CANCEL;
		}

		SetModify();
	}

	//	Hardware version

	if (COWD_SET_HW_VER(m_Sec0.Flags) &&
		m_Sec3.HardwareVer != COWD_HARDWARE_VMWARE2 &&
		m_Sec3.HardwareVer != COWD_HARDWARE_VMWARE3) {

		CHAR ver[10];

		cbparams[1] = ver;

		sprintf(ver, "%lu", m_Sec3.HardwareVer);

		m_Sec3.HardwareVer = VDiskCallBack(
			VDISK_CB_HARDWAREVER, cbparams);

		if (m_Sec3.HardwareVer != COWD_HARDWARE_VMWARE2 &&
			m_Sec3.HardwareVer != COWD_HARDWARE_VMWARE3) {
			return VDK_CANCEL;
		}

		SetModify();
	}

	//
	//	Store capacity
	//
	if (m_Sec0.Version == COWD_FILEVER_VMWARE2) {
		m_nCapacity	= m_Sec0.Capacity;
	}
	else {
		m_nCapacity	= m_Sec3.FileCapacity;
	}

	return VDK_OK;
}

//
//	Update COWDisk header
//
VDKSTAT VDiskExtCowd::Update()
{
	HANDLE			hFile;
	VDKSTAT			ret;

	if (!IsModified()) {
		return VDK_OK;
	}

	ret = VdkOpenFile(&hFile, m_pFullPath, strlen(m_pFullPath), FALSE);

	if (ret != VDK_OK) {
		return ret;
	}

	ret = UpdateFile(hFile);

	VdkCloseFile(hFile);

	ClrModify();

	return ret;
}

void VDiskExtCowd::CreateHeader(VDisk *pDisk, ULONG ordinal)
{
	ULONG			disk_flags;
	ULONG			vmware_ver;
	ULONG			ulong_tmp;

	VdkZeroMem(&m_Sec0, sizeof(m_Sec0));
	VdkZeroMem(&m_Sec2, sizeof(m_Sec2));
	VdkZeroMem(&m_Sec3, sizeof(m_Sec3));

	vmware_ver = pDisk->GetVMwareVer();
	disk_flags = pDisk->GetFlags();

	m_Sec0.Signature	= COWD_SIGNATURE;

	if (vmware_ver <= 2) {
		m_Sec0.Version			= COWD_FILEVER_VMWARE2;
		m_Sec0.Granularity		= COWD1_DEFAULT_GRANULARITY;
	}
	else {
		m_Sec0.Version			= COWD_FILEVER_VMWARE3;
		m_Sec0.Granularity		= COWD3_DEFAULT_GRANULARITY;

		m_Sec3.FileOrdinal		= ordinal;
		m_Sec3.FilesPerDisk		= pDisk->GetExtentCnt();
		m_Sec3.FileCapacity		= COWD3_MAX_EXTENT_SPARSE;
		m_Sec3.HardwareVer		= pDisk->GetHardwareVer();
		m_Sec3.ToolsFlag		= pDisk->GetToolsFlag();

		if (!(disk_flags & VDISK_FLAG_CHILD)) {
			m_Sec3.Cylinders	= pDisk->GetCylinders();
			m_Sec3.Tracks		= pDisk->GetTracks();
			m_Sec3.Sectors		= pDisk->GetSectors();
			m_Sec3.DiskCapacity	= pDisk->GetCapacity();
		}

		if (m_Sec3.HardwareVer) {
			m_Sec0.Flags	|= COWD_FLAG_HW_VER;
		}

		if (m_Sec3.FilesPerDisk > 1) {
			m_Sec0.Flags	|= COWD_FLAG_MULTI;
		}
	}

	m_Sec2.ParentTS		= pDisk->GetParentTS();
	m_Sec2.TimeStamp	= pDisk->GetTimeStamp();
	m_Sec3.TimeStamp	= m_Sec2.TimeStamp;

	if (pDisk->GetController() == VDISK_CONTROLLER_IDE) {
		m_Sec3.Controller	= COWD_CONTROLLER_IDE;
	}
	else {
		m_Sec3.Controller	= COWD_CONTROLLER_SCSI;
	}

	if ((disk_flags & VDISK_FLAG_CHILD)) {
		m_Sec0.Capacity = pDisk->GetCapacity();

		strcpy(m_Sec0.u.ParentPath, pDisk->GetParentPath());
	}
	else {
		m_Sec0.Flags |= COWD_FLAG_ROOT;

		if (pDisk->GetCapacity() == m_nCapacity) {
			//
			//	VMware 2.x virtual disk or single extent virtual disk
			//
			m_Sec0.Capacity				= m_nCapacity;
			m_Sec0.u.Geometry.Cylinders	= pDisk->GetCylinders();
			m_Sec0.u.Geometry.Tracks	= pDisk->GetTracks();
			m_Sec0.u.Geometry.Sectors	= pDisk->GetSectors();
		}
		else {
			//
			//	VMware 3.x multi extent virtual disk
			//
			if (m_Sec3.Controller == COWD_CONTROLLER_IDE) {
				m_Sec0.u.Geometry.Sectors	= COWD_SECTORS_IDE;
				m_Sec0.u.Geometry.Tracks	= COWD3_TRACKS_IDE;
			}
			else {
				if (m_nCapacity <=
					COWD_SECTORS_SCSI_1023M * COWD_TRACKS_SCSI_1023M * 1023) {

					m_Sec0.u.Geometry.Sectors	= COWD_SECTORS_SCSI_1023M;
					m_Sec0.u.Geometry.Tracks	= COWD_TRACKS_SCSI_1023M;
				}
				else {
					m_Sec0.u.Geometry.Sectors	= COWD_SECTORS_SCSI_2046M;
					m_Sec0.u.Geometry.Tracks	= COWD_TRACKS_SCSI_2046M;
				}
			}

			ulong_tmp =
				m_Sec0.u.Geometry.Sectors *
				m_Sec0.u.Geometry.Tracks;

			m_Sec0.u.Geometry.Cylinders =
				m_nCapacity / ulong_tmp;

			m_Sec0.Capacity =
				m_Sec0.u.Geometry.Cylinders * ulong_tmp;
		}
	}

	m_Sec0.PrimaryMapOffset = COWD_PRIMARY_MAP_OFFSET;

	ulong_tmp = m_Sec0.Granularity * COWD_SECONDARY_MAP_SIZE;

	m_Sec0.PrimaryMapSize =
		(m_Sec0.Capacity + ulong_tmp - 1) / ulong_tmp;

	m_Sec0.EndOfFile = COWD_PRIMARY_MAP_OFFSET +
		((m_Sec0.PrimaryMapSize + 127) / 128);
}

//
//	Create actural extent file
//
VDKSTAT VDiskExtCowd::Create(ULONG flags)
{
	HANDLE			hFile;
	VDKSTAT			ret;

	ret = VdkCreateFile(&hFile, m_pFullPath, (flags & VDISK_CREATE_FORCE));

	if (ret != VDK_OK) {
		return ret;
	}

	ret = UpdateFile(hFile);

	VdkCloseFile(hFile);

	return ret;
}

//
//	Write COWD header
//
VDKSTAT VDiskExtCowd::UpdateFile(HANDLE hFile)
{
	COWD_HEADER	cowd;
	VDKSTAT		ret;

	VdkZeroMem(&cowd, sizeof(cowd));

	VdkCopyMem(&cowd.sec0, &m_Sec0, sizeof(m_Sec0));
	VdkCopyMem(&cowd.sec2, &m_Sec2, sizeof(m_Sec2));
	VdkCopyMem(&cowd.sec3, &m_Sec3, sizeof(m_Sec3));

	ret = VdkWriteFileAt(hFile, 0, &cowd, sizeof(cowd), NULL);

	if (ret != VDK_OK) {
		VdkCloseFile(hFile);

		return ret;
	}

	ret = VdkSetFileSize(hFile, (INT64)m_Sec0.EndOfFile << VDK_BYTE_SHIFT_TO_SECTOR);

	if (ret == VDK_OK) {
		m_nFileSize = (INT64)m_Sec0.EndOfFile << VDK_BYTE_SHIFT_TO_SECTOR;
	}

	return ret;
}