Virtual Hard Disk Image (VHD)の基本情報を取得する

Virtual PCで利用されている拡張子VHDのハードディスクイメージファイルのフッター情報を読み込む。このファイルのフォーマットはMicrosoftが公開しているのでそれを参考にした。

ここではVHDファイルに共通に含まれるフッター情報のみを読み込む。
フッター情報はVHDファイルの末尾512Bytesのデータで、VHDファイルの固有識別子、容量、セクター数、VHD種別(固定容量か可変容量か)などの基本情報が格納されている。

サンプルコードはvhdファイルを開いて、ファイル末尾512bytesを読み込む。そしてチェックサムなどのチェックなどが正しければVHD種別などを表示する。

依存環境:ATL
#include "atlstr.h"


//
//	バイト配列をひっくり返す
//
//例:0x1234 -> 0x3412
//
#define	SWAP_BYTE_ALIGNMENT(data)	\
{									\
	int		i;						\
	int		nSize;					\
	int		nLoop;					\
	BYTE*	pData;					\
	BYTE	cbTmp;					\
									\
	pData = (BYTE*)&data;			\
	nSize = sizeof(data);			\
	nLoop = nSize / 2;				\
	for(i = 0; i < nLoop; i++)		\
	{								\
		cbTmp = *(pData + i);		\
		*(pData + i) = *(pData + nSize - i - 1);	\
		*(pData + nSize - i - 1) = cbTmp;			\
	}								\
}



class	CDnpVHDFooter
{
	//
	//	VHDのフッター内で使用される構造体
	//
	#pragma pack(push,1)
	struct	VHD_DISK_GEOMETRY
	{
		SHORT	nCylinder;
		BYTE	nHeads;
		BYTE	nSectorsPerTrackCylinder;
	};
	#pragma pack(pop)


	//
	//	VHDのフッター構造体
	//
	#pragma pack(push,1)
	struct	VHD_FOOTER
	{
		BYTE		pcbCookie[8];				//"conectix"
		DWORD		dwFeatures;					//
		DWORD		dwFileFormatVersion;		//=0x00010000
		ULONGLONG	nDataOffset;
		DWORD		dwTimeStamp;				//2000/1/1/12:00:00UTCからの秒数
		BYTE		pcbCreatorApplication[4];
		DWORD		dwCreatorVersion;
		DWORD		dwCreatorHostOS;
		ULONGLONG	nOriginalSize;
		ULONGLONG	nCurrentSize;
		VHD_DISK_GEOMETRY	sDiskGeometry;
		DWORD		dwDiskType;
		DWORD		dwChecksum;
		BYTE		pcbUniqueId[16];
		BYTE		cbSavedState;
		BYTE		pcbReserved[427];
	};
	#pragma pack(pop)

public:

	//フッター情報
	VHD_FOOTER		_sFooter;


	CDnpVHDFooter()
	{
		::ZeroMemory(&_sFooter,sizeof(VHD_FOOTER));
	}


	//
	//	指定されたファイルハンドルからVirtual Hard Driveのフッター情報を読み込む
	//
	bool	LoadFooter(HANDLE hFile)
	{
		BOOL	ret;
		DWORD	dwRead;

		::SetFilePointer(hFile,-512,NULL,FILE_END);
		ret = ::ReadFile(hFile,&_sFooter,sizeof(VHD_FOOTER),&dwRead,NULL);
		if(ret == FALSE || dwRead != sizeof(VHD_FOOTER))
		{
			::ZeroMemory(&_sFooter,sizeof(VHD_FOOTER));
			return	false;
		}

		//バイト配列をintel形式に変更
		SWAP_BYTE_ALIGNMENT(_sFooter.dwChecksum);
		SWAP_BYTE_ALIGNMENT(_sFooter.dwCreatorHostOS);
		SWAP_BYTE_ALIGNMENT(_sFooter.dwCreatorVersion);
		SWAP_BYTE_ALIGNMENT(_sFooter.dwDiskType);
		SWAP_BYTE_ALIGNMENT(_sFooter.dwFeatures);
		SWAP_BYTE_ALIGNMENT(_sFooter.dwFileFormatVersion);
		SWAP_BYTE_ALIGNMENT(_sFooter.dwTimeStamp);
		SWAP_BYTE_ALIGNMENT(_sFooter.nCurrentSize);
		SWAP_BYTE_ALIGNMENT(_sFooter.nDataOffset);
		SWAP_BYTE_ALIGNMENT(_sFooter.nOriginalSize);
		SWAP_BYTE_ALIGNMENT(_sFooter.sDiskGeometry.nCylinder);

		return	IsValidFooter();
	}



	//
	//	フッター情報が正しいかのチェック
	//
	//完全にはチェックしていない!
	//
	bool	IsValidFooter(void)
	{
		//cookieは"conectix"
		if(::memcmp(_sFooter.pcbCookie,"conectix",8))
		{
			::ZeroMemory(&_sFooter,sizeof(VHD_FOOTER));
			return	false;
		}

		//ファイルフォーマットバージョンは0x00010000
		if(_sFooter.dwFileFormatVersion != 0x00010000)
		{
			::ZeroMemory(&_sFooter,sizeof(VHD_FOOTER));
			return	false;
		}

		//作成OSはWindowsかMac
		if(_sFooter.dwCreatorHostOS != 0x5769326b && _sFooter.dwCreatorHostOS != 0x4d616320)
		{
			::ZeroMemory(&_sFooter,sizeof(VHD_FOOTER));
			return	false;
		}

		//チェックサムのチェック
		DWORD	i;
		DWORD	dwChecksum;
		DWORD	dwCurrent;

		dwCurrent = _sFooter.dwChecksum;
		_sFooter.dwChecksum = 0;
		dwChecksum = 0;
		for(i = 0; i < sizeof(VHD_FOOTER); i++)
			dwChecksum += ((BYTE*)&_sFooter)[i];
		_sFooter.dwChecksum = dwCurrent;
		if(dwCurrent != ~dwChecksum)
		{
			::ZeroMemory(&_sFooter,sizeof(VHD_FOOTER));
			return	false;
		}

		return	true;
	}


	//
	//	イメージファイルが固定サイズかどうか
	//
	bool	IsFixedVHD(void)
	{
		if(IsValidFooter() == false)
			return	false;
		if(_sFooter.dwDiskType == 2)
			return	true;
		return	false;
	}

	//
	//	イメージファイルが可変サイズかどうか
	//
	bool	IsDynamicVHD(void)
	{
		if(IsValidFooter() == false)
			return	false;
		if(_sFooter.dwDiskType == 3)
			return	true;
		return	false;
	}

	//
	//	イメージファイルが差分かどうか
	//
	bool	IsDifferencingVHD(void)
	{
		if(IsValidFooter() == false)
			return	false;
		if(_sFooter.dwDiskType == 4)
			return	true;
		return	false;
	}
};




bool	LoadOnlyFooter(LPCTSTR pszVHDFile)
{
	bool			ret;
	HANDLE			hFile;
	CDnpVHDFooter	cFooter;
	CAtlString		strTmp;
	CAtlString		strMessage;

	hFile = ::CreateFile(pszVHDFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if(hFile == INVALID_HANDLE_VALUE)
		return	false;

	ret = cFooter.LoadFooter(hFile);
	::CloseHandle(hFile);


	if(ret == false)
		return	false;

	if(cFooter.IsDifferencingVHD())
		strMessage = _T("差分VHD\n");
	else if(cFooter.IsDynamicVHD())
		strMessage = _T("可変容量VHD\n");
	else if(cFooter.IsFixedVHD())
		strMessage = _T("固定容量VHD\n");

	strTmp.Format(_T("シリンダー数:%d\nヘッダー数:%d\nセクター数/シリンダー:%d\n容量:%dbytes"),cFooter._sFooter.sDiskGeometry.nCylinder,cFooter._sFooter.sDiskGeometry.nHeads,cFooter._sFooter.sDiskGeometry.nSectorsPerTrackCylinder,cFooter._sFooter.nOriginalSize);
	strMessage += strTmp;

	::MessageBox(NULL,strMessage,_T(""),MB_OK);

	return	true;
}


#undef	SWAP_BYTE_ALIGNMENT




void	Test(void)
{
	bool	ret;

	ret = LoadOnlyFooter(_T("Fixed3MB.vhd"));
	if(ret == false)
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);

	ret = LoadOnlyFooter(_T("Dynamic3MB.vhd"));
	if(ret == false)
		::MessageBox(NULL,_T("取得に失敗しました"),_T(""),MB_OK);
}

プロジェクトファイルをダウンロード


カテゴリー「システム情報」 のエントリー