打开磁盘:
procedure OpenDiskEx(drive:string);
begin
hDriveHandle:=CreateFile(Pchar(drive),GENERIC_ALL,FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0);
end;
读磁盘数据:
procedure ReadDisk(Outdat:pointer;SectorCount:dword;SectorStart:int64);
var
p: PChar;
offe:int64;
begin
if (hDriveHandle <> INVALID_HANDLE_VALUE) then
begin
p:=allocmem(SectorCount * ByteSPerSector);
offe:=SectorStart * BytesPerSector;
FSeek64(hDriveHandle, offe, 0); //起始扇区
if FileRead(hDriveHandle,p[0],integer(SectorCount * BytesperSector))<> integer(SectorCount * BytesperSector) then //读扇区
raise Exception.Create('Read Disk Error!(Dk0001)');
copymemory(Outdat,@p[0],SectorCount * ByteSPerSector);
FreeMem(p, SectorCount * BytesperSector);
end;
end;
读DBR 的BPB 获取 MFT参数:
procedure GetDBR_BPB(SectorStart:int64);
var ctr:pchar;
temp:array of byte;
begin
ctr := allocmem(512); //BPB就1个扇区就够了
setlength(temp,$54);
ReadDisk(ctr,1,SectorStart);
copymemory(@temp[0],@ctr[0],$54);
FreeMem(ctr,512);
copymemory(@dbrs.FatID[1],@temp[3],$20); //只拷贝我关心的数据
copymemory(@dbrs.PTotSec,@temp[$28],$20);
end;
获取文件列表:
procedure TForm1.GetWJList;
var Temp,pAss: pBYTE; //
pIndexAss: pBYTE;
MftLen:integer;
last,j,k,i:integer;
IndexName,FileName:array[0..256*2-1] of char; //索引名
IndexNameLen,FileNameLen:UINT; //索引名长度
Len:LARGE_INTEGER; //文件指针
filena:string;
dwLen:DWORD;
pIndex:PBYTE;
begin
if ListView1.Selected = nil then exit;
listview2.Clear;
Temp :=allocmem(1024); //每个文件2个扇区 = 512*2 =1024
pIndexAss := allocmem(512);
pIndex := allocmem(4096); //一个索引记录一般是4096
OpenDiskEx(ComboBox1.Text);
ReadDisk(Temp,2,MFTSectors+2*5); //$root 在第6个FILE 5#
CloseDisk;
//去掉MFT头 和 尾尺寸 的净尺寸
MftLen := pNTFS_MFT_FILE_HEAD(Temp).mftsize - pNTFS_MFT_FILE_HEAD(Temp).Firstattribute - 8;
if (pdword(Temp)^ = $454C4946) then //必须是“FILE”才可以
begin
dword(temp):=pNTFS_MFT_FILE_HEAD(Temp).Firstattribute + dword(temp);
while( MftLen>0 ) do
begin
case pNTFS_ATTRIBUTE_HEAD(temp).Attribute of
$30: //用30属性来判断是不是$root
begin
dword(pAss) := dword(temp) + pNTFS_FILENAME_HEAD(temp).AttributeContentOffset;
FileNameLen :=pNTFS_FILENAME_ATTRIBUTE(pAss).FileNameLen ;
dword(pAss):=dword(@pNTFS_FILENAME_ATTRIBUTE(pAss).FileName);
//转换文件名
k := WideCharToMultiByte( CP_ACP,WC_COMPOSITECHECK,LPCWSTR(pAss),FileNameLen,pchar(@FileName[0]),254*2,NiL,NiL);
pbyte(@(FileName[k]))^:=0;
filena:= FileName;
if filena <> '.' then exit; //不是$root文件退出
end;
//还是没有完善..要能够适应1簇=2扇区,4扇区,8扇区.....等等多种情况才可以...现在还是固定读8扇区.
$A0: // 索引分配 这个主要是找Runlist ,并读取索引缓冲,得到文件列表
begin
pAss := temp;
dword(pAss) := dword(pAss) + $48; // RunList 位置
if not RunAnalyze(pAss) then exit; //list不正确、没有退出
for j :=1 to FMapOut[0].NumsOfLcn do //每次一个RUN
begin
Len.QuadPart := FMapOut[j].StartLcn;
Len.QuadPart := Len.QuadPart * dbrs.SecPerClu+DBRAdres; //偏移是以DBR的地址为基准的
for i :=1 to (FMapOut[j].NumsOfLcn div (8 div dbrs.SecPerClu)) do //每次一个索引记录,通常为4k
begin
OpenDiskEx(ComboBox1.Text);
ReadDisk(pIndex,8,Len.QuadPart); //读取8个扇区的索引
CloseDisk;
if (pDWORD(pIndex)^ <> $58444E49) then //不是INDX标示就终止
break;
pAss:= pIndex;
last:=0;
dword(pAss) := dword(pAss) + $18; //在索引偏移18H的地方是第一个索引项开始偏移量
dword(pAss) := dword(pAss) + pDWORD(pAss)^; //这个偏移量是相对偏移18H这个地址开始计算的
while(Last < 2 ) do //INDEX_ITEM在偏移0Ch的地方标示了最后索引项
begin
IndexNameLen := PNTFS_INDEX_ITEM(pAss).FileNameLen;
fillmemory(pIndexAss ,512 ,0);
copymemory(pIndexAss,@(PNTFS_INDEX_ITEM(pAss).FileName),IndexNameLen*2) ;
k := WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,
LPCWSTR(pIndexAss),IndexNameLen,@IndexName[0],254*2,NiL,NiL);
pbyte(@(IndexName[k]))^:=0;
filena:= IndexName;
if filena <> '' then
with listview2.items.add do
Caption:=filena;
dword(pAss) := dword(pAss) + PNTFS_INDEX_ITEM(pAss).IndexLen;
Last := PNTFS_INDEX_ITEM(pAss).IndexSign;
end;
end;
end;
end;
end;
MftLen := MftLen - pNTFS_ATTRIBUTE_HEAD(Temp).AllLen;
dword(Temp) := dword(Temp) + pNTFS_ATTRIBUTE_HEAD(Temp).AllLen;
end;
end;
end;
runlist分析的代码参考网上C代码,因为人家比我写的好,精炼!!
function RunAnalyze(RunListData:PBYTE):boolean;
var
Temp:PBYTE; //用于操作runlist的临时指针
StaClusBits:byte; //runlist开始簇占用的list位数
ClusSizBits:byte; //runlist簇的大小占用的list位数
RunCount:integer; //runlist里面run的个数
StartCluster:DWORD; //开始簇
ClusterSize:WORD; //簇的大小
begin
//初始化参数为0
RunCount := 0; //当前运行的个数
StartCluster := 0;
ClusterSize := 0;
Temp := RunListData; //取得run指针
while temp^ > 0 do //当第一个字节为0 就结束了
begin
StaClusBits := Temp^ shr 4 ; //开始的簇 取高位 得到 开始簇占用的list位数
ClusSizBits := Temp^ and $F; //长度 取低位 得到 簇的大小占用的list位数
//一个run项目的大小 = 1+ (ClusSizBits + StaClusBits) 如:32 那么这个listsize = 1+(2+3)=6
//排列方式:type size Cluster
if(StaClusBits = 0)then begin
//遇到 01的情况,开始蔟号还必须加上 上次的cluster 的大小
StartCluster := StartCluster + ClusterSize ;
end; {}
inc(temp); //temp指针移动一位到 簇的大小 位置
ClusterSize:=pWORD(temp)^ and ( $FFFF shr (16- 8*ClusSizBits));
inc(temp,ClusSizBits); //temp指针移动*位到 开始簇 位置
//开始簇是和前面叠加的
StartCluster:=StartCluster + (pDWORD(temp)^ and ($FFFFFF shr (24-8*StaClusBits)));
inc(temp,StaClusBits); //temp指针移动*位到 下一个runlist 位置
RunCount:=RunCount+1; //有就+1 最后就是所有run的数目了;
if(RunCount>4095) then break;
//填充输出FMapOut结构
FMapOut[0].NumsOfLcn := RunCount;
FMapOut[RunCount].StartLcn := StartCluster and $FFFFFF;
FMapOut[RunCount].NumsOfLcn := ClusterSize;
end;
result:=true;
end;
列出的第一分区文件,还没有区分文件与文件夹(这个比较简单)
就这样吧........遍历就遍历吧.....