Virtual Hard Disk Image (VHD)のヘッダー情報も取得する

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

ここでは前回作成した「Virtual Hard Disk Image (VHD)の基本情報を取得する」にヘッダー情報読み込み用のソースコードを追加して、可変容量VHDファイルと差分VHDファイルのみに含まれるヘッダー情報を読み込む。

ヘッダー情報はファイル先頭512bytesの位置から512bytesのサイズ書き込まれている。ただし固定容量VHDの場合はヘッダー情報がない。そのため、先にフッター情報を参照して固定容量VHDではないことを確認する必要がある。

ここでは前回からの追加部分のみを掲載する。ダウンロード可能なプロジェクトには全ソースコードを含んでいる。

依存環境:ATL
class	CDnpVHDHeader
{

	//
	//	VHDのヘッダー内で利用される構造体
	//
	#pragma pack(push,1)
	struct	PARENT_LOCATOR_ENTRY
	{
		DWORD		dwPlatformCode;
		DWORD		dwPlatformDataSpace;
		DWORD		dwPlatformDataLength;
		BYTE		pcbReserved[4];
		LONGLONG	nPlatformDataOffset;
	};
	#pragma pack(pop)


	//
	//	VHDのヘッダー構造体
	//
	//容量可変VHD、差分VHDでのみ使われる
	//
	#pragma pack(push,1)
	struct	VHD_HEADER_DYNAMIC
	{
		BYTE		pcbCookie[8];
		LONGLONG	nDataOffset;
		LONGLONG	nTableOffset;
		DWORD		dwHeaderVersion;
		DWORD		dwMaxTableEntries;
		DWORD		dwBlockSize;
		DWORD		dwChecksum;
		BYTE		pcbParentUniqueId[16];
		DWORD		dwParentTimeStamp;
		BYTE		pcbReserved1[4];
		WCHAR		pwszParentUnicodeName[512/2];
		PARENT_LOCATOR_ENTRY	psParentLocatorEntry[8];
		BYTE		pcbReserved2[256];
	};
	#pragma pack(pop)
public:

public:

	//ヘッダー情報
	VHD_HEADER_DYNAMIC		_sHeader;


	CDnpVHDHeader()
	{
		::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC));
	}


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

		::SetFilePointer(hFile,512,NULL,FILE_BEGIN);
		ret = ::ReadFile(hFile,&_sHeader,sizeof(VHD_HEADER_DYNAMIC),&dwRead,NULL);
		if(ret == FALSE || dwRead != sizeof(VHD_HEADER_DYNAMIC))
		{
			::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC));
			return	false;
		}

		//バイト配列をintel形式に変更
		SWAP_BYTE_ALIGNMENT(_sHeader.dwBlockSize);
		SWAP_BYTE_ALIGNMENT(_sHeader.dwChecksum);
		SWAP_BYTE_ALIGNMENT(_sHeader.dwHeaderVersion);
		SWAP_BYTE_ALIGNMENT(_sHeader.dwMaxTableEntries);
		SWAP_BYTE_ALIGNMENT(_sHeader.dwParentTimeStamp);
		SWAP_BYTE_ALIGNMENT(_sHeader.nDataOffset);
		SWAP_BYTE_ALIGNMENT(_sHeader.nTableOffset);

		for(j = 0; j < 8; j++)
		{
			SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].dwPlatformCode);
			SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].dwPlatformDataLength);
			SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].dwPlatformDataSpace);
			SWAP_BYTE_ALIGNMENT(_sHeader.psParentLocatorEntry[j].nPlatformDataOffset);
		}

		return	IsValidHeader();
	}


	//
	//	ヘッダー情報が正しいかのチェック
	//
	//完全にはチェックしていない!
	//
	bool	IsValidHeader(void)
	{
		//cookieは"conectix"
		if(::memcmp(_sHeader.pcbCookie,"cxsparse",8))
		{
			::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC));
			return	false;
		}

		if(_sHeader.nDataOffset != -1)
		{
			::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC));
			return	false;
		}

		//作成OSはWindowsかMac
		if(_sHeader.dwHeaderVersion != 0x00010000)
		{
			::ZeroMemory(&_sHeader,sizeof(VHD_HEADER_DYNAMIC));
			return	false;
		}

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

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

		return	true;
	}


};





bool	LoadFooterAndHeader(LPCTSTR pszVHDFile)
{
	bool			ret;
	bool			bHasHeader;
	HANDLE			hFile;
	CDnpVHDFooter	cFooter;
	CDnpVHDHeader	cHeader;
	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);
	if(ret == false)
	{
		::CloseHandle(hFile);
		return	false;
	}

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

	if(bHasHeader)
	{
		bHasHeader = cHeader.LoadHeader(hFile);
		if(bHasHeader == false)
			strMessage += _T("(ヘッダー情報の取得に失敗しました)\n");
	}

	::CloseHandle(hFile);

	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;
}



void	Test(void)
{
	bool	ret;

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

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

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

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


カテゴリー「コラム」 のエントリー