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