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

📄 diskfs.pas

📁 国外著名恢复软件Drive_Rescue 公布的早期源码 版本是1.8 delphi6环境开发的。
💻 PAS
📖 第 1 页 / 共 5 页
字号:
{ FAT File System Module, Copyright (C) 2001, 2002 by Alexander Grau }

{ FAT file system structure:

   |----|-------|-------|-------|------------|----------------------------|
   | BS | FAT 1 |  ...  | FAT n | root 12/16 |  data area                 |
   |----|-------|-------|-------|------------|----------------------------|

   example for FAT12:

   1. boot sector                       sector 0 (in partition)
   2. first FAT   (4085 Cluster)
   3. second FAT
   4. root directory (32 Byte/entry)
   5. data area (data cluster)

  Remark: Long filename support has nothing to do with FAT32! FAT32 is only used for big volumes. }

unit diskfs;

interface

uses classes, devices, comctrls, statusdlg;

const
  { user defined FAT Type constants }
  FATnone = 0  ; { not detected }
  FAT12   = 1  ;
  FAT16   = 2  ;
  FAT32   = 3  ;

  { user defined cluster types }
  clusUsed  = 1;
  clusFree  = 2;
  clusBad   = 4;
  clusEOF   = 8;

  attrReadOnly   = 1;               { File Attribute }
  attrHidden     = 2;
  attrSystem     = 4;
  attrVolume     = 8;
  attrSubDir     = 16;
  attrArchive    = 32;
  attrLongName   = attrReadOnly + attrHidden + attrSystem + attrVolume;


type

  PBootSec = ^TBootSec;
  {: Boot Sector and BPB Structure }
  TBootSec = packed record
    BS_jmpBoot     : array[0..2] of byte;
    BS_OEMName     : array[0..7] of char;
   { ;-----now the BPB (BIOS Parameter Block) begins ---------------------------------- }
    BPB_BytesPSec  : word;
    BPB_SecPerClus : byte;
    BPB_RsvdSecCnt : word;
    BPB_NumFATs    : byte;
    BPB_RootEntCnt : word;
    BPB_TotSec16   : word;
    BPB_Media      : byte;
    BPB_FATsz16    : word;
    BPB_SecPerTrk  : word;
    BPB_NumHeads   : word;
    BPB_HiddSec    : longword;
    BPB_TotSec32   : longword;
    {;------now the BPB/boot sector for FAT12/16 differs from the BPB/boot sector for FAT32...}
    BS_DrvNum      : byte;
    BS_Reserved1   : byte;
    BS_BootSig     : byte;
    BS_VolID       : longword;
    BS_VolLab      : array[0..10] of char;
    BS_FilSysType  : array[0..7] of char;
    {; ... Loader Routine follows ...}
  end;


  PBootSec32 = ^TBootSec32;
  {: boot sector structure for FAT32 }
  TBootSec32 = packed record
    BS_jmpBoot     : array[0..2] of byte;
    BS_OEMName     : array[0..7] of char;
   { ;-----now the BPB (BIOS Parameter Block) begins ---------------------------------- }
    BPB_BytesPSec  : word;
    BPB_SecPerClus : byte;
    BPB_RsvdSecCnt : word;
    BPB_NumFATs    : byte;
    BPB_RootEntCnt : word;
    BPB_TotSec16   : word;
    BPB_Media      : byte;
    BPB_FATsz16    : word;
    BPB_SecPerTrk  : word;
    BPB_NumHeads   : word;
    BPB_HiddSec    : longword;
    BPB_TotSec32   : longword;
    { ;------now the BPB/boot sector for FAT32 differs from the BPB/boot sector for FAT12/16... }
    BPB_FATSz32    : longword;
    BPB_ExtFlags   : word;
    BPB_FSVer      : word;
    BPB_RootClus   : longword;
    BPB_FSInfo     : word;
    BPB_BkBootSec  : word;
    BPB_Reserved   : array[0..11] of byte;
    BS32_DrvNum    : byte;
    BS32_Reserved1_: byte;
    BS32_BootSig   : byte;
    BS32_VolID     : array[0..3] of byte;
    BS32_VolLab    : array[0..10] of char;
    BS32_FilSysType: array[0..7] of char;
  end;


  {: FAT32 FSInfo Sector Structure }
  TFSInfo = packed record
     FSI_LeadSig   : longword;
     FSI_Reserved1 : array[0..479] of byte;
     FSI_StrucSig  : longword;
     FSI_FreeCount : longword;
     FSI_NxtFree   : longword;
     FSI_Reserved2 : array[0..11] of byte;
     FSI_TrailSig  : longword;
  end;


  {: 32 Byte Directory Entry Structure }
  PDirEntry = ^TDirEntry;
  TDirEntry = packed record
    DIR_Name         : array[0..10] of byte;
    DIR_Attr         : byte;
    DIR_NTRes        : byte;
    DIR_CrtTimeTenth : byte;
    DIR_CrtTime      : word;
    DIR_CrtDate      : word;
    DIR_LstAccDate   : word;
    DIR_FstClusHI    : word;
    DIR_WrtTime      : word;
    DIR_WrtDate      : word;
    DIR_FstClusLO    : word;
    DIR_FileSize     : longword;
  end;

  PLnDirEntry = ^TLnDirEntry;
  {: Long Name Directory Entry Structure }
  TLnDirEntry = packed record
    DIR_Sig          : byte;
    DIR_LName1       : array[0..4] of word;
    DIR_Attr         : byte;
    DIR_Flags        : byte;
    DIR_ChkSum       : byte;
    DIR_LName2       : array[0..5] of word;
    DIR_First        : word;
    DIR_LName3       : array[0..1] of word;
  end;

  {: Information structure for Reset, Blockread }
  TFATFileInfo = record
    FI_FirstClus: longword; { erster Cluster }
    FI_Cluster  : longword; { aktueller Cluster }
    FI_recpos   : longword; { current record position (0 to filesize-1) }
    FI_size     : longword; { file size }
    FI_LastClus : longword; { last used cluster (for blockwrite) }
  end;


  { File }
  TFATFile = class (TCustomFile)
  public
    attr: byte;
    cluster: longword;
    time, date: word;
    procedure duplicate(dest: TCustomFile); override;
    function Rename(aname: string): boolean; override;
    function GetPath(RelativeToDir: TCustomDirectory): string; override;
    procedure SaveTo(dest: string; FATno: byte; dlg: TStatusDialog); virtual;
    procedure ChangeListViewItem(listitem: TListItem); override;
  end;

  { Directory }
  TFATDirectory = class (TCustomDirectory)
  public
    cluster: longword;
    sector: longword;    // if FAT12/16 root directory, this is the sector (and cluster = 0)
    time, date: word;
    procedure duplicate(dest: TCustomDirectory); override;
    function Rename(aname: string): boolean; override;
    function GetPath(RelativeToDir: TCustomDirectory): string; override;
    procedure AddDirToTree(TreeView: TTreeView; node: TTreeNode; deleted: boolean); override;
    procedure ChangeListViewItem(listitem: TListItem); override;
    procedure AddChildrenToListView(listview: TListView; deleted: boolean); override;
    function CompareChildren(item1, item2: TListItem; useIdx: integer): integer; override;
    procedure ForEachChild(proc: TProcessDirProc; deleted, exclusive, recursive: boolean;
      UserParams: integer); virtual;
    function ChildIsSubDir: boolean; override;
  private
    function SubDirFound(finddeleted: boolean): boolean;
    //function IsValid: boolean;
    procedure AddChildren(deleted, exclusive: boolean);
  end;

  TFATAnalyser = class;  

  {: The FAT drive object }
  TFATdrive = class(TCustomDrive)
  public
    { current options }
    useFAT             : byte;        // use: 0=no FAT, 1=first, 2=second FAT
    skipBadMarkedClus  : boolean;     // skip bad marked cluster?

    BootSec            : TBootSec32; { Boot sector of device (accessed via BootSec/BootSec32 structure) }
    FSInfo            : TFSInfo;     { FSInfo Structure }

    { optional parameters calculated from the boot sector... }
    FATtype           : byte;        { determined FAT type (FAT12, FAT16 or FAT32) }
    TotSec            : longword;    { Total count of sectors }
    BytePerClus       : word;        { Bytes per Cluster }
    RootClus          : longword;
    RootDirSectors    : word;        { Sectors occupied by the root directory }
    FirstRootDirSecNum: longword;
    FATsz             : longword;    { Count of sectors occupied by ONE FAT }
    FATSectors        : longword;    { Sectors occupied by all FATs }
    FirstDataSector   : longword;    { Start of the data region, the first sector of cluster 2 }
    TotDataSec        : longword;    { Data sector count }
    CountOfClusters   : longword;    { Total count of Clusters }

    constructor Create; override;
    destructor Destroy; override;
    function ReadSec(LBA: longint; blocks: word; buf: pointer; ErrorDlg: boolean): boolean; override;
    function MountDrive(quiet: boolean): boolean; override;
    procedure FindLostData(dlg: TStatusDialog); override;
    procedure AddDriveToTree(TreeView: TTreeView); override;
    procedure AddListViewColumns(ListView: TListView); override;
    function FindFiles: boolean; override;
    procedure SaveListViewItems(ListView: TListView); override;
    function SaveFile(afile: TfatFile; dest: string; FATno: byte;
      dlg: TStatusDialog; var overwrite: boolean): integer;
    function SaveDirectory(dir: TfatDirectory; dest: string;
      deleted, exclusive, recursive: boolean; FATno: byte;
      dlg: TStatusDialog; var overwrite: boolean; var fileoverwrite: boolean): integer;

    function CalcDriveInfo(pbs: PBootSec; quiet: boolean): boolean;
    function GetFAT(N: longword; FATno: byte): longword;
    function GetClusterMask(clustype: byte): longword;
    function IsEOF(value: longword): boolean;

    function Cluster2Sec(cluster: longword): longword;
    function Sec2Cluster(sec: longword): longword;

    function ReadDataSec(var cluster: longword; var sector: longword; var clussec: word; xferbuf: pointer): boolean;    
    function GetNextRecord(var cluster: longword; var sector: longword; var recno: word; xferbuf: pointer): boolean;
    function GetLongName(var cluster: longword; var recsec: longword; var recno: word;
      entry: PDirEntry; var longname: string): boolean;
    function FindNextEntry(var cluster: longword; var recsec: longword; var recno: word;
      var entry: TDirentry; var name: string; findDeleted: boolean): boolean;

    function ResetByCluster(cluster, size: longword; var handle: TFATFileInfo): boolean;
    function BlockRead(var handle: TFATFileInfo; count: longword; buf: pointer;  FATno: byte;
      var bytesread: longword): boolean;
    function GetRecPosCluster(var N: longword; recpos: longword; FATno: byte): boolean;
    function Seek(var handle: TFATFileInfo; N: longword; FATno: byte): boolean;
    function filepos(handle: TFATFileInfo): longword;
    function filesize(handle: TFATFileInfo): longword;
    procedure Close(var handle: TFATFileInfo);
  private
    { sector buffers }
    FFATSecBuf         : array[0..512*2 -1] of byte; { 2 Sectors FAT Buffer (2 because FAT12 can bound a sector!) }
    FFATSec            : longword;                  { current FAT sector in buffer }
    FFATchg            : byte;  { 0=FAT not changed / 1=first sector changed, 2=both sectors changed (FAT12 only) }

    FWorkSecBuf        : array[0..511] of byte; { Working Sector Buffer for getnextrecord }
    FWorkSec           : longword;              { current working sector in buffer }

    FDataSecBuf        : array[0..511] of byte; { Data Sector Buffer for Blockread }
    FDataSec           : longword;              { current data sector in buffer }
    FFATAnalyser       : TFATAnalyser;
    procedure CreateStartItems;
  end;


  {: The FAT drive analyser }
  TFATAnalyser = class
  public
    AnalyseDev: TDevice;     // device to analyse
    LastFATsec: longword;    // last FAT sector found
    MaxFATclus: longword;    // last maximum FAT cluster number

    FirstFATsecbuf: pointer; // first FAT sector buffer
    FATstartsec: longword;   // FAT start sector (of all FATs)
    FATendsec: longword;     // FAT end sector   (of all FATs)
    NumberOfFATsFound: byte; // number of FATs found
    OneFATsecsize: longword; // sector size of one FAT
    fattype: byte;           // FAT type found

    FATAreafound: boolean;   // FAT area found?
    DataAreaFound: boolean;  // data area found?
    RootAreaFound: boolean;  // Root area found?

    SecPerClus   : word;     // sectors per cluster
    ClusterCount: longword;  // count of clusters
    FirstDirClus: longword;  // cluster of first directory found
    FirstDirSec: longword;   // sector of first directory found
    FirstDataSec: longword;  // sector of first data cluster (cluster 2)

    succSecValidEntries: byte; // number of succesive sectors with valid entries

    RootSec: longword;       // root directory sector
    RootClus: longword;      // root directory cluster (=0 if not found)
    RootEntCnt: word;        // number of root directory entries
    succSecValidEntriesRoot: byte; // number of successive sectors with valid entries in the root area

    function CnvName(buf: pointer): shortstring;
    function ClusterType(FATtype: byte; value: longword): byte;

    function IsBlankEntry(entry: TDirEntry): boolean;

    function IsBootSecB(p: pointer): boolean;
    function AreBootSecEqualB(p1, p2: pointer): boolean;
    function DirEntriesValidB(buf: pointer; bufsize: word;
      ValidClusterCount, ValidTotalDataSec: longword): boolean;
    function GetNextRecordB(buf: pointer; bufsize: longword; var recno: word; xferbuf: pointer): boolean;
    function IsFATbeginB(buf: pointer; bufsize: longword; FATtype: byte): boolean;
    function IsFATB(buf: pointer; bufsize: longword; var IsFATbegin: boolean; var FATtype: byte;
      var maxclus: longword): boolean;
    function IsDirB(buf: pointer; bufsize: longword; var cluster: longword): boolean;
    function IsRootB(buf: pointer; bufsize: longword): boolean;
    function GetFATB(buf: pointer; bufsize: longword; FATtype: byte; N: longword): longword;

    function IsRootC(drv: TfatDrive; clus, sec: longword): boolean;
    function IsDirC(drv: TfatDrive; clus, sec: longword): boolean;
    function DirEntriesValidC(drv: TfatDrive; clus, sec: longword): boolean;
    function IsDirEmptyC(drv: TfatDrive; clus, sec: longword): boolean;
    function IsFileC(drv: TfatDrive; scanclus: longword; var fileext: string; var datatype: byte): boolean;

    procedure AnalyseSecStart(dev: TDevice);
    procedure AnalyseSecStop;
    function AnalyseSec(dev: TDevice; physsec: longword; buf: pointer; bufsize: longword): boolean;
    procedure AnalyseRestart;

    procedure RebuildBootSec(dev: TDevice; pbs: pbootsec32; FATtype, SecPerclus: word;
      RootEntCnt: word; RootClus: longword;
      OneFATsecSize: longword; NumFATs: byte;
      ClusterCount: longword);
  end;


  {: FAT file stream object, for easy use with text/hex viewer etc. }
  TFATStream = class(TStream)
  private
    FPosition: longint;
    FSize: longint;
    Fcluster: longint;
    Fdrv: TfatDrive;
    FFATno: byte;
    Fhandle: TfatFileInfo;
    procedure SetPosition(offset: longint);
  public
    property position: longint read FPosition write SetPosition;
    property size: longint read Fsize;
    constructor create(drv: TfatDrive; clus, size: longint; FATno: byte);
    destructor destroy; override;
    function read(var buffer; count: longint): longint; override;
    function seek(offset: longint; origin: word): longint; override;
  end;


  function ReplaceDeletedChar(const s: string): string;



implementation

  uses common, windows, sysutils, main, clusdlg, helpers, dialogs, finddlg, dirseldlg, controls, filedet;


function ReplaceDeletedChar(const s: string): string;
begin
  if MainForm.options.DeletedUseMultiByte then
    result:=StringReplace(s, char($e5), MainForm.options.DeletedCharMultibyte, [])
  else
    result:=StringReplace(s, char($e5), MainForm.options.DeletedCharAnsi, []);
end;

// ---------------------------------------------------------------------------
//  TfatAnalyser
// ---------------------------------------------------------------------------

function TFATAnalyser.CnvName(buf: pointer): shortstring;
var
  i: byte;
  ext, name, res: shortstring;
  c: ^char;
begin
  name:=''; ext:='';
  i:=0; c:=buf;
  while (i < 11) do
  begin
    if (c^ <> ' ') then
    begin
      if (i < 8) then name:=name+c^
        else ext:=ext+c^;
    end;
    inc(i);
    inc(c);
  end;
  res:=name;
  if ext <> '' then res:=res+'.'+ext;
  CnvName:=res;
end;


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -