📄 diskfs.pas
字号:
value:=longword((@pbytearray(buf)^[offset])^) and $0fffffff
else if FATtype = FAT12 then
begin
value:=word((@pbytearray(buf)^[offset])^);
if (N AND 1 <> 0) then
value:=value SHR 4
else value:=value and $0fff;
end;
result:=value;
end;
// checks if part of FAT found (and if FAT begins)
function TFATAnalyser.IsFATB(buf: pointer; bufsize: longword; var IsFATbegin: boolean;
var FATtype: byte; var maxclus: longword): boolean;
var
i, j: integer;
clus, lastclus: longword;
ftype: byte;
max, succclus, cluscount: longword;
samecount: longword;
fbegin: boolean;
startclus: longword;
begin
result:=FALSE;
for ftype := FAT32 downto FAT12 do
begin
fbegin:=IsFATbeginB(buf, bufsize, ftype);
case ftype of
FAT12: cluscount:=(2*bufsize + bufsize) DIV 4; // DIV 1.5 without float
FAT16: cluscount:=bufsize DIV 2;
FAT32: cluscount:=bufsize DIV 4;
end;
lastclus:=0; succclus:=0; max:=0;
if NOT fbegin then startclus:=0
else startclus:=2;
for i:=startclus to cluscount-1 do
begin
clus:=GetFATB(buf, bufsize, ftype, i);
if ClusterType(ftype, clus) = clusEOF then
begin
lastclus:=0;
end else if ClusterType(ftype, clus) = clusUsed then
begin
// check if there are multiple equal cluster numbers...
samecount:=0;
for j:=startclus to cluscount-1 do
if (j <> i) AND (clus = GetFATB(buf, bufsize, ftype, j)) then inc(samecount);
if samecount > 4 then
begin
succclus:=0; break;
end;
if clus > max then max:=clus;
if clus = lastclus + 1 then inc(succclus);
lastclus:=clus;
end;
end;
if succclus > 16 then
begin
result:=TRUE; FATtype:=ftype; maxclus:=max; IsFATbegin:=fbegin;
exit;
end;
end;
end;
//-------- Find lost drives analyser -----------------
// starts FAT sector analyser
procedure TFATAnalyser.AnalyseSecStart(dev: TDevice);
begin
AnalyseDev:=dev;
getmem(FirstFATsecbuf, AnalyseDev.BytesPerSec);
AnalyseRestart;
end;
procedure TFATAnalyser.AnalyseRestart;
begin
FATAreaFound:=FALSE;
MaxFATclus:=0;
LastFATsec:=0;
FATstartsec:=0;
FATendsec:=0;
NumberOfFATsfound:=0;
OneFATsecsize:=0;
FirstDataSec:=0;
FirstDirClus:=0; FirstDirSec:=0;
DataAreaFound:=FALSE;
ClusterCount:=0;
SecPerClus:=0;
RootAreaFound:=FALSE;
RootClus:=0;
RootEntCnt:=0;
RootSec:=0;
succSecValidEntries:=0;
succSecValidEntriesRoot:=0;
end;
// stops FAT sector analyser
procedure TFATAnalyser.AnalyseSecStop;
begin
freemem(FirstFATsecbuf, AnalyseDev.BytesPerSec);
end;
procedure TFATAnalyser.RebuildBootSec(dev: TDevice; pbs: pbootsec32; FATtype, SecPerclus: word;
RootEntCnt: word; RootClus: longword;
OneFATsecSize: longword; NumFATs: byte;
ClusterCount: longword);
var
drv: TFATdrive;
totalsec: longword;
RootDirSectors: longword;
DataSectors: longword;
begin
fillchar(pbs^, sizeof(tbootsec32), 0);
pbs^.BPB_BytesPSec:=512;
pbs^.BPB_SecPerClus:=SecPerClus;
pbs^.BPB_RsvdSecCnt:=1; // let sector 0 begin one sector before the FAT
pbs^.BPB_RootEntCnt:=RootEntCnt;
RootDirSectors:=((pbs^.BPB_RootEntCnt * 32) + (pbs^.BPB_BytesPSec - 1)) div pbs^.BPB_BytesPSec;
DataSectors:=ClusterCount * pbs^.BPB_SecPerClus;
if fattype = FAT32 then
begin
pbs^.BPB_FATsz16:=0;
pbs^.BPB_FATSz32:=OneFATSecSize;
end else
begin
pbs^.BPB_FATsz16:=OneFATSecSize;
end;
pbs^.BPB_NumFATs:=NumFATs;
totalsec:=pbs^.BPB_RsvdSecCnt + (pbs^.BPB_NumFATs * OneFATSecSize) + RootDirSectors + DataSectors;
if totalsec > $FFFF then
begin
pbs^.BPB_TotSec16:=0;
pbs^.BPB_TotSec32:=totalsec;
end else
begin
pbs^.BPB_TotSec16:=totalsec;
end;
if (dev.attr AND DEVICE_ATTR_REMOVABLE <> 0) then
pbs^.BPB_Media:=$F0
else
pbs^.BPB_Media:=$F8;
if fattype = FAT32 then pbs^.BPB_RootClus:=RootClus;
end;
{ |----|-------|-------|-------|------------|----------------------------|
| BS | FAT 1 | ... | FAT n | root 12/16 | data area |
|----|-------|-------|-------|------------|----------------------------| }
// process new sector by FAT sector analyser
function TFATAnalyser.AnalyseSec(dev: TDevice; physsec: longword; buf: pointer; bufsize: longword): boolean;
var
maxclus: longword;
dummy: integer;
IsFATbegin: boolean;
fatfound: boolean;
diff: word;
clus: longword;
validentries, dirfound: boolean;
newdrv: tfatDrive;
begin
if physsec = 95 then // part1: FAT1: sec 95-9225 FAT2: sec 9226-18356 clus 2: sec 18357 (clus count 1168442)
begin
//hexdump(pbytearray(buf)^, bufsize);
end;
if NOT DataAreaFound then
begin
fatfound:=IsFATB(buf, bufsize, IsFATbegin, fattype, maxclus);
if fatfound then
begin
// FAT sector found...
FATareafound:=TRUE;
if maxclus > MaxFATclus then MaxFATclus:=maxclus;
if IsFATbegin then
begin
// First FAT sector...
if (FATstartsec=0) then
begin
// first time FAT found...
FATstartsec:=physsec;
inc(NumberOfFATsFound);
move(buf^, FirstFATsecbuf^, 512); // remember first FAT sector
end else
begin
// this may be a copy of the first FAT...
diff:=BytesEqual(buf, FirstFATsecbuf, 512);
if diff < 16 then
begin
// this is a copy of the first one...
inc(NumberOfFATsFound);
FATendsec:=physsec-1;
OneFATsecsize:=FATendsec-FATstartsec+1;
end;
end;
end;
LastFATSec:=physsec;
end;
end;
if FATareafound then
begin
if Clustercount = 0 then
begin
case FATtype of
FAT12: ClusterCount:=OneFATSecsize * 512 DIV 2-2;
FAT16: ClusterCount:=(2*OneFATSecsize * 512 + OneFATSecsize * 512) DIV 4-2; // x 1.5 without float...
FAT32: ClusterCount:=OneFATSecsize * 512 DIV 4-2;
end;
end;
dirfound:=IsDirB(buf, bufsize, clus);
validentries:=DirEntriesValidB(buf, bufsize, clustercount, clustercount*128);
if validentries then // determine successive sector with valid directory entries...
inc(succSecValidEntries)
else
succSecValidEntries:=0;
if (NOT dirfound) AND (validentries) AND (IsRootB(buf, bufsize)) then
begin
// this "may be" the root...
RootAreaFound:=TRUE;
RootSec:=physsec;
succSecValidEntriesRoot:=succSecValidEntries;
end;
if dirfound then
begin
// data area and directory found...
DataAreaFound:=TRUE;
if FirstDirClus = 0 then
begin
// first directory found...
FirstDirClus:=clus;
FirstDirSec:=physsec;
end else
begin
// second directory found ?...
if SecPerClus = 0 then
begin
SecPerClus:=(physsec-FirstDirSec) DIV (clus-FirstDirClus);
firstDataSec:=physsec - (clus-2) * SecPerClus;
if FATendsec=0 then
begin
// no FAT copy found before...
FATendsec:=firstDataSec-1;
OneFATsecsize:=FATendsec-FATstartsec+1;
end;
// --- now FAT and data area are found... ----------
debug(Format('FAT startsec: %d, endsec: %d', [FATstartsec, FATendsec]), debugHIGH);
debug(Format('data startsec: %d', [firstDataSec]), debugHIGH);
end;
end;
end;
if (RootAreaFound) AND (SecPerClus <> 0) then
begin
// sector per clusters is known...
// check if all sectors of the root clusters are successive valid entries...
RootAreaFound:=(succSecValidEntriesRoot >= (RootSec-firstDataSec) MOD SecPerClus);
end;
if (RootAreaFound) AND (SecPerClus <> 0) then
begin
// --- now all FAT, data area and root are found... ----------
RootClus:=(RootSec-firstDataSec) DIV SecPerClus +2;
debug(Format('root clus: %d'#13, [rootclus]), debugHIGH);
newdrv:=tfatdrive.create;
MainForm.DrvList.drives.add(newdrv);
RebuildBootSec(dev, @newdrv.bootsec, fattype, secperclus, rootentcnt, rootclus,
oneFATsecSize, NumberOfFATsFound, ClusterCount);
newdrv.dev:=dev;
newdrv.condition := drv_cond_virtual + drv_cond_bootsecRebuild;
// let the drive begin one sector before the FAT...
newdrv.PosBootSec:=FATstartsec-1;
newdrv.PartOfs:=FATstartsec-1;
newdrv.CalcDriveInfo(@newdrv.bootsec, TRUE);
newdrv.PartSectors:=newdrv.TotSec;
newdrv.name:=newdrv.name + 'DRIVE (without BootSec)';
newdrv.CreateStartItems;
AnalyseRestart; // restart the FAT analyser...
result:=TRUE;
exit;
end;
end;
result:=FALSE;
end;
// ---------------------------------------------------------------------------
// TfatDrive
// ---------------------------------------------------------------------------
constructor TFATdrive.Create;
begin
FFATAnalyser := TFATAnalyser.create;
end;
destructor TFATdrive.Destroy;
var
i : Integer;
begin
if assigned(RootDir) then RootDir.free;
if assigned(RootDirDeleted) then RootDirDeleted.free;
if assigned(RootDirLost) then RootDirLost.Free;
if assigned(RootDirSearched) then RootDirSearched.free;
FFATAnalyser.free;
end;
{ Read partition Sector (FDD uses only LBA:word) to address buf }
function TFATdrive.ReadSec(LBA: longint; blocks: word; buf: pointer; ErrorDlg: boolean): boolean;
var
res: boolean;
begin
res:=dev.ReadSec(PartOfs + LBA, blocks, buf, ErrorDlg);
result:=res;
end;
(*{ Write partition Sector (FDD uses only LBA:word) to address buf }
function TFATdrive.WritePartSec(drvno: byte; LBA: longint; buf: pointer): boolean;
var
res: boolean;
begin
{res:=ExtendedWrite($80+currDrive, Dev[devno].DI_PartOfs + LBA, 1, buf);}
WritePartSec:=res;
end;*)
{ Converts cluster to a logical sector number }
function TFATdrive.Cluster2Sec(cluster: longword): longword;
begin
Cluster2Sec:=FirstDataSector + (cluster-2) * BootSec.BPB_SecPerClus;
end;
function TFATdrive.MountDrive(quiet: boolean): boolean;
var
BS: array[0..511] of byte;
res: boolean;
begin
res:=false;
if ReadSec(PosBootSec-PartOfs, 1, @BS, true) then
begin
Hexdump(BS[0], sizeof(BS));
move(BS, BootSec, sizeof(TBootSec32));
res:=CalcDriveInfo(@bootsec, quiet);
CreateStartItems;
end;
result:=res;
end;
procedure TFATdrive.CreateStartItems;
var
item: TFATdirectory;
begin
// create TFatDirectory objects for 'root' and 'root deleted'
// add root dir...
item:=TFATDirectory.create;
item.cluster:=RootClus;
item.sector:=FirstRootDirSecNum;
item.name:='Root';
item.expanded:=false;
item.flags:=0;
item.drive:=self;
RootDir:=item;
// add deleted dirs...
item:=TFATDirectory.create;
item.cluster:=RootClus;
item.sector:=FirstRootDirSecNum;
item.name:='Deleted';
item.expanded:=false;
item.flags:=0;
item.drive:=self;
RootDirDeleted:=item;
// lost dir and searched dir have both children already assigned (so there will not be executed 'AddChildren'!)
// add lost dir...
item:=TFATDirectory.create;
item.cluster:=0;
item.sector:=0;
item.name:='Lost';
item.expanded:=false;
item.flags:=0;
item.drive:=self;
item.children:=TList.create;
RootDirLost:=item;
// add searched dir...
item:=TFATDirectory.create;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -