⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diskfs.pas

📁 国外著名恢复软件Drive_Rescue 公布的早期源码 版本是1.8 delphi6环境开发的。
💻 PAS
📖 第 1 页 / 共 5 页
字号:
    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 + -