Virtual PCで利用されている拡張子VHDのハードディスクイメージファイルのヘッダー情報を読み込む。このファイルのフォーマットはMicrosoftが公開しているのでそれを参考にした。
ここでは前回作成した「Virtual Hard Disk Image (VHD)の基本情報を取得する」にヘッダー情報読み込み用のソースコードを追加して、可変容量VHDファイルと差分VHDファイルのみに含まれるヘッダー情報を読み込む。
ヘッダー情報はファイル先頭512bytesの位置から512bytesのサイズ書き込まれている。ただし固定容量VHDの場合はヘッダー情報がない。そのため、先にフッター情報を参照して固定容量VHDではないことを確認する必要がある。
ここでは前回からの追加部分のみを掲載する。ダウンロード可能なプロジェクトには全ソースコードを含んでいる。
依存環境:ATLclass 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);
}
