📄 diskfs.pas
字号:
function TFATAnalyser.ClusterType(FATtype: byte; value: longword): byte;
var
res: byte;
begin
if value = 0 then res:=clusFree
else res:=clusUsed;
begin
case FATtype of
FAT12: begin
if value >= $0ff8 then res:=clusEOF
else if value >= $0ff1 then res:=clusBad;
end;
FAT16: begin
if value >= $fff8 then res:=clusEOF
else if value >=$fff1 then res:=clusBad;
end;
FAT32: begin
if value >= $0ffffff8 then res:=clusEOF
else if value >= $0ffffff1 then res:=clusBad;
end;
end;
end;
ClusterType:=res;
end;
function TFATAnalyser.IsBootSecB(p: pointer): boolean;
type
tbuf= array[0..511] of byte;
var
pbs: pbootsec;
pbuf: ^tbuf;
valid: boolean;
i: integer;
begin
valid:=false;
pbs:=p; pbuf:=p;
if (pbuf^[510]=$55) AND (pbuf^[511]=$aa) AND (pbuf^[0]=$eb) then
begin
for i:=8 to 12 do
begin
if (pbs^.BPB_BytesPSec) = word(2 SHL i) then valid:=true;
end;
end;
IsBootSecB:=valid;
end;
function TFATAnalyser.AreBootSecEqualB(p1, p2: pointer): boolean;
type
pbuf= array[0..511] of byte;
var
pbs1: pbootsec;
pbs2: pbootsec;
buf: ^pbuf;
begin
result:=FALSE;
pbs1:=p1;
pbs2:=p2;
if pbs1^.BPB_BytesPSec <> pbs2^.BPB_BytesPSec then exit;
if pbs1^.BPB_SecPerClus <> pbs2^.BPB_SecPerClus then exit;
if pbs1^.BPB_RsvdSecCnt <> pbs2^.BPB_RsvdSecCnt then exit;
if pbs1^.BPB_NumFATs <> pbs2^.BPB_NumFATs then exit;
if pbs1^.BPB_RootEntCnt <> pbs2^.BPB_RootEntCnt then exit;
if pbs1^.BPB_TotSec16 <> pbs2^.BPB_TotSec16 then exit;
if pbs1^.BPB_FATsz16 <> pbs2^.BPB_FATsz16 then exit;
if pbs1^.BPB_SecPerTrk <> pbs2^.BPB_SecPerTrk then exit;
if pbs1^.BPB_NumHeads <> pbs2^.BPB_NumHeads then exit;
if pbs1^.BPB_HiddSec <> pbs2^.BPB_HiddSec then exit;
if pbs1^.BPB_TotSec32 <> pbs2^.BPB_TotSec32 then exit;
result:=TRUE;
end;
{ checks if entry is blank }
function TFATAnalyser.IsBlankEntry(entry: TDirEntry): boolean;
var
noblanks: word;
i: integer;
begin
result:=FALSE;
noblanks:=0;
for i:=0 to sizeof(entry)-1 do
if byte(pointer(longint(@entry)+i)^) <> 0 then inc(noblanks);
if noblanks = 0 then result:=TRUE;
end;
function TFATAnalyser.DirEntriesValidC(drv: TfatDrive; clus, sec: longword): boolean;
var
currclus: longword;
recsec: longword;
clussec: word;
secbuf: array[0..511] of byte;
begin
if clus = 11393 then
begin
//debug('root!', debugHigh);
end;
if drv.ReadDataSec(clus, sec, clussec, @secbuf[0]) then
begin
currclus:=clus; recsec:=sec;
result:=DirEntriesValidB(@secbuf[0], 512, drv.CountOfClusters, drv.TotDataSec);
end else result:=FALSE;
end;
{ sec paramter is only used if clus=0 ! (for FAT12/16) }
function TFATAnalyser.DirEntriesValidB(buf: pointer; bufsize: word;
ValidClusterCount, ValidTotalDataSec: longword): boolean;
var
no: integer;
recno: word;
entry: TDirEntry;
shortname: shortstring;
i: integer;
entclus: longword;
longfound: boolean;
res: boolean;
begin
recno:=0;
result:=FALSE; longfound:=FALSE;
for no:=1 to 16 do
begin
res:=GetNextRecordB(buf, bufsize, recno, @entry);
if (NOT res) then exit;
// check if first entry used => if not, this is NOT a directory...
if no = 1 then if entry.DIR_Name[0]=0 then {IsBlankEntry(entry) then} exit;
with TLnDirEntry(entry) do
if ( ((DIR_Attr = $0f) AND (DIR_First = 0) AND (DIR_sig AND $40=$40) )
OR ((DIR_Attr = $0f) AND (DIR_First = 0) AND longfound) ) then
begin
{ Long file name entry found... }
longfound:=TRUE;
end else
begin
longfound:=FALSE;
//debug(cnvname(@entry.dir_name), debugHigh);
{ short file name entry... }
{ check valid short filename (not valid are e.g. : '\', '/', ':', '*', '?', '"', '<', '>', '\') }
for i:=0 to 10 do
begin
if (entry.DIR_Name[i] < $20) then
begin
if (i > 0) then exit; { values less 20hex not legal }
if entry.DIR_Name[0] <> $05 then exit; { only one case: KANJI lead byte => then deleted is 05hex, not 0E5hex! }
end else if byte(entry.DIR_Name[i]) IN [$22, $2A, $2B, $2C, $2E, $2F, $3A, $3B, $3C, $3D, $3E, $3F, $5B, $5C, $5D, $7C] then exit;
end;
{ check cluster value }
entclus:=entry.DIR_FstClusLO OR (longint(entry.DIR_FstClusHI) SHL 16);
if (entry.DIR_attr AND attrVolume <> 0) then
begin
if entclus <> 0 then exit; // volume label must be cluster 0
end else if (entclus < 2) OR (entclus > ValidClusterCount+1) then exit;
{ check attribute }
if (entry.DIR_Attr AND 192) <> 0 then exit;
{ check file size }
if longword(entry.DIR_FileSize div 512) > longword(ValidTotalDataSec) then exit;
{ check date / time }
{ write time/date (must be supported) }
if entry.DIR_WrtTime <> 0 then
begin
if (entry.DIR_WrtTime AND 31) > 29 then exit;
if ((entry.DIR_WrtTime SHR 5) AND 63) > 59 then exit;
if (entry.DIR_WrtTime SHR 11) > 23 then exit;
end;
if entry.DIR_WrtDate <> 0 then
begin
if (entry.DIR_WrtDate AND 31 > 31) OR (entry.DIR_WrtDate AND 31 = 0) then exit;
if (((entry.DIR_WrtDate SHR 5) AND 15) > 12) OR ((entry.DIR_WrtDate SHR 5) AND 15 = 0) then exit;
end;
if entry.DIR_CrtTime <> 0 then
begin
if (entry.DIR_CrtTime AND 31) > 29 then exit;
if ((entry.DIR_CrtTime SHR 5) AND 63) > 59 then exit;
if (entry.DIR_CrtTime SHR 11) > 23 then exit;
end;
if entry.DIR_CrtDate <> 0 then
begin
if (entry.DIR_CrtDate AND 31 > 31) OR (entry.DIR_CrtDate AND 31 = 0) then exit;
if (((entry.DIR_CrtDate SHR 5) AND 15) > 12) OR ((entry.DIR_CrtDate SHR 5) AND 15 = 0) then exit;
end;
if entry.DIR_LstAccDate <> 0 then
begin
if (entry.DIR_LstAccDate AND 31 > 31) OR (entry.DIR_LstAccDate AND 31 = 0) then exit;
if (((entry.DIR_LstAccDate SHR 5) AND 15) > 12) OR ((entry.DIR_LstAccDate SHR 5) AND 15 = 0) then exit;
end;
end;
end;
result:=TRUE;
end;
{ There should only be one "file" on the volume that has the volume attribute set, and that file must be in the root directory.
This name of this file is actually the label for the volume. DIR_FstClusHI and DIR_FstClusLO must always be 0 for the volume label
(no data clusters are allocated to the volume label file). }
// sec is only used if clus = 0 (for FAT12/16)
function TFATAnalyser.IsRootC(drv: TfatDrive; clus, sec: longword): boolean;
var
no: integer;
recno: word;
currclus: longword;
entry: TDirEntry;
volfound: boolean;
recsec: longword;
res: boolean;
begin
currclus:=clus; recsec:=sec;
recno:=0;
volfound:=FALSE;
for no:=1 to (drv.BootSec.BPB_SecPerClus * 16) do
begin
res:=drv.GetNextRecord(currclus, recsec, recno, @entry);
if (NOT res) then break;
with TLnDirEntry(entry) do
if NOT (DIR_Attr = $0f) AND (DIR_First = 0) AND (DIR_sig AND $40=$40) then // no long file name...
begin
if (entry.DIR_attr AND attrVolume <> 0) AND (entry.DIR_FstClusHI = 0) AND (entry.DIR_FstClusLO = 0) then
begin
if volfound then // more than one volume label => no root!
begin
result:=FALSE;
exit;
end else volfound:=TRUE;
end;
end;
end;
result:=volfound;
end;
function TFATAnalyser.IsDirC(drv: TfatDrive; clus, sec: longword): boolean;
var
currclus: longword;
recno: word;
entry: TDirEntry;
recsec: longword;
res: boolean;
begin
recno:=0; currclus:=clus; recsec:=sec;
res:=drv.GetNextRecord(currclus, recsec, recno, @entry);
if (res) AND (entry.DIR_attr AND attrSubDir <>0) AND (CnvName(@entry.DIR_name) = '.') then
begin
res:=drv.GetNextRecord(currclus, recsec, recno, @entry);
if (res) then
begin
if (entry.DIR_attr AND attrSubDir <>0) AND (CnvName(@entry.DIR_name) = '..') then
begin
result:=TRUE;
exit;
end;
end;
end;
result:=FALSE;
end;
{ checks if directory is empty }
function TFATAnalyser.IsDirEmptyC(drv: TfatDrive; clus, sec: longword): boolean;
var
lfname: string;
currclus, recsec: longword;
res: boolean;
recno: word;
entry: TDirEntry;
begin
result:=TRUE;
recsec:=sec; currclus:=clus;
recno:=2;
res:=drv.FindNextEntry(currclus, recsec, recno, entry, lfname, FALSE);
if res then result:=FALSE;
end;
function TFATAnalyser.IsFileC(drv: TfatDrive; scanclus: longword; var fileext: string; var datatype: byte): boolean;
var
buf: pointer;
res: boolean;
begin
getmem(buf, drv.bootsec.BPB_SecPerClus*512);
try
res:=drv.ReadSec(drv.Cluster2Sec(scanclus), drv.bootsec.BPB_SecPerClus, buf, TRUE);
if res then res:=filedet.IsFile(buf, drv.bootsec.BPB_SecPerClus*512, fileext, datatype)
finally
freemem(buf, drv.bootsec.BPB_SecPerClus*512);
end;
result:=res;
end;
function TFATAnalyser.GetNextRecordB(buf: pointer; bufsize: longword; var recno: word; xferbuf: pointer): boolean;
var
recsec: longword;
res: boolean;
secentry: word;
begin
if (recno+1) * 32 <= bufsize then
begin
move(pointer(longword(buf)+recno*32)^, xferbuf^, 32);
inc(recno);
result:=TRUE;
end else result:=FALSE;
end;
function TFATAnalyser.IsDirB(buf: pointer; bufsize: longword; var cluster: longword): boolean;
var
recno: word;
entry: TDirEntry;
res: boolean;
clus: longword;
begin
recno:=0;
res:=GetNextRecordB(buf, bufsize, recno, @entry);
if (res) AND (entry.DIR_attr AND attrSubDir <>0) AND (CnvName(@entry.DIR_name) = '.') then
begin
clus:=entry.DIR_FstClusLO OR (longint(entry.DIR_FstClusHI) SHL 16);
res:=GetNextRecordB(buf, bufsize, recno, @entry);
if (res) then
begin
if (entry.DIR_attr AND attrSubDir <>0) AND (CnvName(@entry.DIR_name) = '..') then
begin
cluster:=clus;
result:=TRUE;
exit;
end;
end;
end;
result:=FALSE;
end;
{ There should only be one "file" on the volume that has the volume attribute set, and that file must be in the root directory.
This name of this file is actually the label for the volume. DIR_FstClusHI and DIR_FstClusLO must always be 0 for the volume label
(no data clusters are allocated to the volume label file). }
// sec is only used if clus = 0 (for FAT12/16)
function TFATAnalyser.IsRootB(buf: pointer; bufsize: longword): boolean;
var
no: integer;
recno: word;
entry: TDirEntry;
volfound: boolean;
res: boolean;
begin
recno:=0;
volfound:=FALSE;
for no:=1 to bufsize DIV 32 do
begin
res:=GetNextRecordB(buf, bufsize, recno, @entry);
if (NOT res) then break;
with TLnDirEntry(entry) do
if NOT (DIR_Attr = $0f) AND (DIR_First = 0) AND (DIR_sig AND $40=$40) then // no long file name...
begin
if (entry.DIR_attr AND attrVolume <> 0) AND (entry.DIR_FstClusHI = 0) AND (entry.DIR_FstClusLO = 0) then
begin
if volfound then // more than one volume label => no root!
begin
result:=FALSE;
exit;
end else volfound:=TRUE;
end;
end;
end;
result:=volfound;
end;
// checks for FAT beginning
function TFATAnalyser.IsFATbeginB(buf: pointer; bufsize: longword; FATtype: byte): boolean;
const
media: array[1..8] of byte = ($F0, $F8, $F9, $FA, $FB, $FC, $FD, $FE);
// $FF is also allowed but used for EOF mark by MS disk driver...
var
i: integer;
res: boolean;
begin
result:=FALSE;
// check BPB_Media byte value...
for i:=1 to 8 do
begin
case FATtype of
FAT12: res:= (pwordarray(buf)^[0]=$0F00 OR media[i]);
FAT16: res:= (pwordarray(buf)^[0]=$FF00 OR media[i]);
FAT32: res:= (plongarray(buf)^[0]=$0FFFFF00 OR media[i]);
end;
if res then
begin
result:=TRUE;
exit;
end;
end;
end;
// get FAT entry number N (for specified buf and FAT type)
function TFATAnalyser.GetFATB(buf: pointer; bufsize: longword; FATtype: byte; N: longword): longword;
var
offset: longword;
value: longword;
begin
if Fattype = FAT16 then
offset:=N*2
else if FATtype = FAT32 then
offset:=N*4
else if FATtype = FAT12 then
offset:=N+(N div 2);
if FATtype = FAT16 then
value:=word((@pbytearray(buf)^[offset])^)
else if FATtype = FAT32 then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -