www.pudn.com > NTFSUndelete_src.zip > NTFSDrive.cpp
// NTFSDrive.cpp: implementation of the CNTFSDrive class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "NTFSDrive.h"
#include "MFTRecord.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNTFSDrive::CNTFSDrive()
{
m_bInitialized = false;
m_hDrive = 0;
m_dwBytesPerCluster = 0;
m_dwBytesPerSector = 0;
m_puchMFTRecord = 0;
m_dwMFTRecordSz = 0;
m_puchMFT = 0;
m_dwMFTLen = 0;
m_dwStartSector = 0;
}
CNTFSDrive::~CNTFSDrive()
{
if(m_puchMFT)
delete m_puchMFT;
m_puchMFT = 0;
m_dwMFTLen = 0;
}
void CNTFSDrive::SetDriveHandle(HANDLE hDrive)
{
m_hDrive = hDrive;
m_bInitialized = false;
}
// this is necessary to start reading a logical drive
void CNTFSDrive::SetStartSector(DWORD dwStartSector, DWORD dwBytesPerSector)
{
m_dwStartSector = dwStartSector;
m_dwBytesPerSector = dwBytesPerSector;
}
// initialize will read the MFT record
/// and passes to the LoadMFT to load the entire MFT in to the memory
int CNTFSDrive::Initialize()
{
NTFS_PART_BOOT_SEC ntfsBS;
DWORD dwBytes;
LARGE_INTEGER n84StartPos;
n84StartPos.QuadPart = (LONGLONG)m_dwBytesPerSector*m_dwStartSector;
// point the starting NTFS volume sector in the physical drive
DWORD dwCur = SetFilePointer(m_hDrive,n84StartPos.LowPart,&n84StartPos.HighPart,FILE_BEGIN);
// Read the boot sector for the MFT infomation
int nRet = ReadFile(m_hDrive,&ntfsBS,sizeof(NTFS_PART_BOOT_SEC),&dwBytes,NULL);
if(!nRet)
return GetLastError();
if(memcmp(ntfsBS.chOemID,"NTFS",4)) // check whether it is realy ntfs
return ERROR_INVALID_DRIVE;
/// Cluster is the logical entity
/// which is made up of several sectors (a physical entity)
m_dwBytesPerCluster = ntfsBS.bpb.uchSecPerClust * ntfsBS.bpb.wBytesPerSec;
if(m_puchMFTRecord)
delete m_puchMFTRecord;
m_dwMFTRecordSz = 0x01<<((-1)*((char)ntfsBS.bpb.nClustPerMFTRecord));
m_puchMFTRecord = new BYTE[m_dwMFTRecordSz];
m_bInitialized = true;
// MFTRecord of MFT is available in the MFTRecord variable
// load the entire MFT using it
nRet = LoadMFT(ntfsBS.bpb.n64MFTLogicalClustNum);
if(nRet)
{
m_bInitialized = false;
return nRet;
}
return ERROR_SUCCESS;
}
//// nStartCluster is the MFT table starting cluster
/// the first entry of record in MFT table will always have the MFT record of itself
int CNTFSDrive::LoadMFT(LONGLONG nStartCluster)
{
DWORD dwBytes;
int nRet;
LARGE_INTEGER n64Pos;
if(!m_bInitialized)
return ERROR_INVALID_ACCESS;
CMFTRecord cMFTRec;
wchar_t uszMFTName[10];
mbstowcs(uszMFTName,"$MFT",10);
// NTFS starting point
n64Pos.QuadPart = (LONGLONG)m_dwBytesPerSector*m_dwStartSector;
// MFT starting point
n64Pos.QuadPart += (LONGLONG)nStartCluster*m_dwBytesPerCluster;
// set the pointer to the MFT start
nRet = SetFilePointer(m_hDrive,n64Pos.LowPart,&n64Pos.HighPart,FILE_BEGIN);
if(nRet == 0xFFFFFFFF)
return GetLastError();
/// reading the first record in the NTFS table.
// the first record in the NTFS is always MFT record
nRet = ReadFile(m_hDrive,m_puchMFTRecord,m_dwMFTRecordSz,&dwBytes,NULL);
if(!nRet)
return GetLastError();
// now extract the MFT record just like the other MFT table records
cMFTRec.SetDriveHandle(m_hDrive);
cMFTRec.SetRecordInfo((LONGLONG)m_dwStartSector*m_dwBytesPerSector, m_dwMFTRecordSz,m_dwBytesPerCluster);
nRet = cMFTRec.ExtractFile(m_puchMFTRecord,dwBytes);
if(nRet)
return nRet;
if(memcmp(cMFTRec.m_attrFilename.wFilename,uszMFTName,8))
return ERROR_BAD_DEVICE; // no MFT file available
if(m_puchMFT)
delete m_puchMFT;
m_puchMFT = 0;
m_dwMFTLen = 0;
// this data(m_puchFileData) is special since it is the data of entire MFT file
m_puchMFT = new BYTE[cMFTRec.m_dwFileDataSz];
m_dwMFTLen = cMFTRec.m_dwFileDataSz;
// store this file to read other files
memcpy(m_puchMFT, cMFTRec.m_puchFileData, m_dwMFTLen);
return ERROR_SUCCESS;
}
/// this function if suceeded it will allocate the buufer and passed to the caller
// the caller's responsibility to free it
int CNTFSDrive::Read_File(DWORD nFileSeq, BYTE *&puchFileData, DWORD &dwFileDataLen)
{
int nRet;
if(!m_bInitialized)
return ERROR_INVALID_ACCESS;
CMFTRecord cFile;
// point the record of the file in the MFT table
memcpy(m_puchMFTRecord,&m_puchMFT[nFileSeq*m_dwMFTRecordSz],m_dwMFTRecordSz);
// Then extract that file from the drive
cFile.SetDriveHandle(m_hDrive);
cFile.SetRecordInfo((LONGLONG)m_dwStartSector*m_dwBytesPerSector, m_dwMFTRecordSz,m_dwBytesPerCluster);
nRet = cFile.ExtractFile(m_puchMFTRecord,m_dwMFTRecordSz);
if(nRet)
return nRet;
puchFileData = new BYTE[cFile.m_dwFileDataSz];
dwFileDataLen = cFile.m_dwFileDataSz;
// pass the file data, It should be deallocated by the caller
memcpy(puchFileData,cFile.m_puchFileData,dwFileDataLen);
return ERROR_SUCCESS;
}
int CNTFSDrive::GetFileDetail(DWORD nFileSeq, ST_FILEINFO &stFileInfo)
{
int nRet;
if(!m_bInitialized)
return ERROR_INVALID_ACCESS;
if((nFileSeq*m_dwMFTRecordSz+m_dwMFTRecordSz) >= m_dwMFTLen)
return ERROR_NO_MORE_FILES;
CMFTRecord cFile;
// point the record of the file in the MFT table
memcpy(m_puchMFTRecord,&m_puchMFT[nFileSeq*m_dwMFTRecordSz],m_dwMFTRecordSz);
// read the only file detail not the file data
cFile.SetDriveHandle(m_hDrive);
cFile.SetRecordInfo((LONGLONG)m_dwStartSector*m_dwBytesPerSector, m_dwMFTRecordSz,m_dwBytesPerCluster);
nRet = cFile.ExtractFile(m_puchMFTRecord,m_dwMFTRecordSz,true);
if(nRet)
return nRet;
// set the struct and pass the struct of file detail
memset(&stFileInfo,0,sizeof(ST_FILEINFO));
wcstombs(stFileInfo.szFilename,cFile.m_attrFilename.wFilename,_MAX_PATH);
stFileInfo.dwAttributes = cFile.m_attrFilename.dwFlags;
stFileInfo.n64Create = cFile.m_attrStandard.n64Create;
stFileInfo.n64Modify = cFile.m_attrStandard.n64Modify;
stFileInfo.n64Access = cFile.m_attrStandard.n64Access;
stFileInfo.n64Modfil = cFile.m_attrStandard.n64Modfil;
stFileInfo.n64Size = cFile.m_attrFilename.n64Allocated;
stFileInfo.n64Size /= m_dwBytesPerCluster;
stFileInfo.n64Size = (!stFileInfo.n64Size)?1:stFileInfo.n64Size;
stFileInfo.bDeleted = !cFile.m_bInUse;
return ERROR_SUCCESS;
}