Модуль для работы с дисковыми драйверами (На уровне FAT)

Модуль для работы с дисковыми драйверами (На уровне FAT)

FAT/FAT16/FAT32
Модуль для работы с дисковыми драйверами
Автор : NikNet
E-MAIL : NikNet@Yandex.ru
Сайт : NikNet.narod.ru [Скоро будет :)]
2006г
Версия 4.00 (Win9x/NT)

Файловая система FAT фирмы Microsoft

FAT12/FAT16 FAT32
Загрузочный сектор Загрузочный сектор
FAT 1 Структура FSInfo
FAT 2 FAT 1
Системная
Корнивой каталог FAT 2 область
Область данных Область данных

unit uFAT;

interface





Uses Windows,SysUtils,DISK,CLASSES;

TYPE

{----------- Структура загрузочного сектора для FAT12 и FAT16 ---------------}

 PBoot = ^TBoot;

 TBoot { }= packed record

 bsJmpBoot { Переход на код загрузки }: array[1..3] of byte;

 bsOemname { Имя пройзводителя }: array[1..8] of char;

 bsBytePerSec { Число байт в секторе }: word;

 bsSecPerClus { Число секторов в сластере }: byte;

 bsRsvdSecCnt { Начала FAT1 в секторах }: word;

 bsNumFATs { Число копий FAT }: byte;

 bsRootEntCnt { Количество элементов в корне }: word;

 bsToolSec12 { Общее количество секторов на диске }: word;

 bsMedia { Тип носителя }: byte;

 bsFATSz16 { Количество в одной FAT }: word;

 bsSecPerTrk { Число секторов на одной дорожки }: word;

 bsNumHeads { Число головок на одной дорожки }: word;

 bsNumHideSec { Количество "скрытых" секторов }: LongInt;

 bsToolSec16 { Общее количество секторов на диске }: LongInt;

 bsDrvNum { Номер дискавода }: byte;

 bsReserved1 { Резервировано для WinNT }: byte;

 bsBootSig { Признак расширеной загрузочной записи (24h) }: byte;

 bsVolID { Серийны номер диска }: LongInt;

 bsVolLab { Метка тома диска }: array[1..11] of char;

 bsFSType { Тип файловой системы }: array[1..8] of char;

 bsBoot { Загрузочный код }: array[1..448]of Byte;

 bsTrailSig { Сигнатура AA55h }: array[1..2] of char;

 end;

{--------------- Структура загрузочного сектора для FAT32 -------------------}

 PBoot32 = ^TBoot32;

 TBoot32 { }= packed record

 bsJmpBoot { Переход на код загрузки }: array[1..3] of byte;

 bsOemname { Имя пройзводителя }: array[1..8] of char;

 bsBytePerSec { Число байт в секторе }: word;

 bsSecPerClus { Число секторов в сластере }: byte;

 bsRsvdSecCnt { Начала FAT1 в секторах }: word;

 bsNumFATs { Число копий FAT }: byte;

 bsRootEntCnt { Количество элементов в корне }: word;

 bsToolSec16 { Зарезервировано }: word;

 bsMedia { Тип носителя }: byte;

 bsFATz16 { Зарезервировано }: word;

 bsSecPerTrk { Число секторов на одной дорожки }: word;

 bsNumHeads { Число головок на одной дорожки }: word;

 bsHiddSec { Число скрытых секторов }: Longint;

 bsTolSec32 { Общее количество секторов на диске }: LongInt;

 bsFATSz32 { Количество сектаров для одной FAT }: LongInt;

 bsExtFlags { Номер активой FAT }: word;

 bsFSVer { Номер версии: старший байт номер версии,младши номер ревизи }: word;

 bsRootClus { Первый кластер обычно имеет номер 2 }: LongInt;

 bsFSInfo { Номер сектора структуры FSINFO }: word;

 bsBkBootSec { Номер BootSector(Копия) обычно имеет номер 2 }: word;

 bsReserved { Облость резервированная }: array[1..12] of byte;

 bsDrvNum { Номер дискавода }: byte;

 bsReserved1 { Резервировано для WinNT }: byte;

 bsBootSig { Признак расширеной загрузочной записи (24h) }: byte;

 bsVolID { Серийны номер диска }: LongInt;

 bsVolLab { Метка тома диска }: array[1..11] of char;

 bsFSType { Тип файловой системы }: array[1..8] of char;

 bsBoot { Загрузочный код }: array[1..420]of byte;

 bsTrailSig { Сигнатура AA55h }: array[1..2] of char;

 end;

{-------------------------> Типы носителей информации <------------------------}const

 MediaType { }:array[1..7] of byte= (

 $F0  { Гибкий диск, 2 стороны, 18 секторов на дорожке },

 $F8  { Жесткий диск },

 $F9  { Гибкий диск, 2 стороны, 15 секторов на дорожке },

 $FC  { Гибкий диск, 1 стороны, 09 секторов на дорожке },

 $FD  { Гибкий диск, 2 стороны, 09 секторов на дорожке },

 $FE  { Гибкий диск, 1 стороны, 08 секторов на дорожке },

 $FF  { Гибкий диск, 2 стороны, 08 секторов на дорожке } );

{----- Структура сектора FSInfo и резервного загрузочного сектора FAT32 -----}Type

 PFsInfo = ^TFsInfo;

 TFsInfo { }= Record

 fsLeadSig { Сигнатура 41615252h }:LongInt;

 fsReserved1 { Зарезервировано }:array[1..480] of byte;

 fsStrucSig { Сигнатура 61417272h }:LongInt;

 fsFree_Count { Количество свободных кластеров }:LongInt;

 fsNxt_Free { Обычно номер 2 }:LongInt;

 fsReserved2 { Зарезервировано }:array[1..12] of byte;

 fsTrailSig { Сигнатура AA550000h }:array[1..4] of byte;

 end;

{------------ Вид начальных фрагментов для FAT различных типов --------------}{

 Байт 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23

 FS12 - FF 8F FF 00 30 04 00 5F FF 00 7F FF FF F0 0A 00 BF FF 00 D0 0E FF FF FF

 FS16 - FF F8 FF FF 00 03 00 04 00 05 FF FF 00 07 FF FF FF FF 00 0A 00 0B FF FF

 FS32 - 0F FF FF F8 0F FF FF FF 00 00 00 03 00 00 00 04 00 00 00 05 0F FF FF FF

  Резервные файлы Конечный

  кластер

  файла

{---------------- Значения специальных кодов элементов FAT ------------------}
{

  Значение кода FAT12 FAT16 FAT32

  Свободный кластер 0 0 0

  Дефектный кластер $FF7 $FFF7 $FFFFFF7

  Последний кластер в списке $FF8-$FFF $FFF8-$FFFF $FFFFFF8-$FFFFFFF}


const

 FAT_Available = 0;

 FAT_Reserved_Min = $FFFFFFF0;

 FAT_Reserved_Max = $FFFFFFF6;

 FAT_BAD = $FFFFFFF7;

 FAT_EOF_Min = $FFFFFFF8;

 FAT_EOF_Max = $FFFFFFFF;

 FAT_MASK_12  = $FFF;

 FAT_MASK_16  = $FFFF;

 FAT_MASK_32  = $FFFFFFF;

const

 ATTR_ARCHIVE = $20; // Архивный

 ATTR_DIRECTORY = $10; // Директория

 ATTR_VOLUME = $08; // Метка тома

 ATTR_SYSTEM = $04; // Системный

 ATTR_HIDDEN = $02; // Скрытый

 ATTR_READONLY  = $01; // Только для чтение

TYPE

{----------------------- Структура элемента каталога ------------------------}

  PDIRENTRY = ^TDIRENTRY;

  TDIRENTRY = record

  Name  { Имя файла или директори }:array[1..8] of char;

  EXT { Расширение файла }:array[1..3] of char;

  Attr { Атрибуты файла }:BYTE;

  NTRes { Поле зарезервировано для WinNT должно содержать 0 }:BYTE;

  CrtTimeTenth { Поле, уточняющее время создание файла в милисикундах }:BYTE;

  CrtTime { Время создание файла }:WORD;

  CrtDate { Дата создание файла }:WORD;

  LstAccDate { Дата последнего обращения к файлу для I/O данных }:WORD;

  FSIClasHi { Старшее слово номера первого кластера файла }:WORD;

  WrtTime { Время выпонения последней операции записи в файл }:WORD;

  WrtDate { Дата выпонения последней операции записи в файл }:WORD;

  FSIClasLo { Младшее слово номера первого кластера файла }:WORD;

  Size { Размер файла в байтах ( 32-разрядное число ) }:LONGINT;

  end;

{--- Структура элемента каталога, хранящего фрагмент длинного имени файла ---}

  PLONGDIRENTRY = ^TLONGDIRENTRY;

  TLONGDIRENTRY = record

  Counter { Номер фрагмента }:Byte;

  LFN1 { Первый участок фрагмента имени }:array[1..5]of Wchar;

  Attr { Атрибуты файла }:BYTE;

  Flags { Байт флагов }:BYTE;

  ChkSum { Контроляная сумма << короткого имени >> }:BYTE;

  LFN2 { Второй участок фрагмента имени }:array[1..6]of Wchar;

  FirstClus { Номер первого кластера ( должен быть равен 0 ) }:Word;

  LFN3 { Третий участок фрагмента имени }:array[1..2]of Wchar;

  end;



{------------------------------------------------------------------------------}

(******************************************************************************)

{------------------------------------------------------------------------------}

(******************************************************************************)

{------------------------------------------------------------------------------}

 TYPE

 TFSType = (fsNone, fsFAT12, fsFAT16, fsFAT32);

 TDIR_Entry = record

  Name  : String;

  LongName : String;

  Ext : String;

  Attr : Byte;

  StartCluster : Longint;

  CreateTime : Longint;

  CreateDate : Longint;

  WriteLastDate : Longint;

  WriteLastTime : Longint;

  FileSize : Longint;

  LastAccessDate : Longint;

  Erased : Boolean;

  CurrentSector : Int64;

  StartByteNamePerSec : Integer;

  end;

 PDIR_Entry = ^TDIR_Entry;



 VAR

 PhysicalVolume : word = 0; // Номер текущего Физичиского диска

 Volume : Byte = 0; // Текущий логический диск

 VolumeSerial : DWord = 0; // Серийный номер тома

 BytesPerSector : DWORD = 0; // Количество байт в одном секторе

 LogicalSectors : Int64 = 0; // Количество секторов на лог. диске

 SectorsPerCluster : DWORD = 0; // Количество секторов в одном кластере

 RootDirSector : Int64 = 0; // Начало корневого каталога

 RootDirCluster : Int64 = 0; // Начальный кластер корневого каталога

 RootDirEntries : Int64 = 0; // Количество элементов в корневом каталоге

 DataAreaSector : Int64 = 0; // Текущий кластер

 FATCount : Byte = 0; // Количество копий FAT (Обычно 2)

 SectorsPerFAT : Int64 = 0; // Количеств секторов в одной FAT

 FATSize : Int64 = 0; // Размер FAT в кластерах

 FATSector : Pointer = nil; // Начало FAT

 FAT : Pointer = nil; // Буфер для файловых элементов

 ActiveFAT : word;

 EndingCluster : Int64 = 0; // Последний кластер для одной FAT



 VolumeName : array[1..11] of char; // Метка тома

 FSName : array [1..8] of Char; // Название файловой системы

 FSType : TFSType = fsNone; // Тип файловой системы



 Function Init (Drive:byte):Boolean;

 Function ReadSector (Sector: Int64; Count: Word; Var Buffer; nSize:DWORD): Boolean;

 Function WriteSector (Sector: Int64; Count: Word; Var Buffer; nSize:DWORD): Boolean;

 Function GetFATCluster(FATIndex: LongInt): LongInt;

 Function GetFATEntry (Cluster: Int64): Longint;

 Procedure SetFATEntry (Cluster: Int64; Value: Longint);

 Function GetCluster(Sector: Int64):Int64;

 Function ReadCluster (Cluster: Int64; var Buffer; BufferSize: Longint): Boolean;

 Function WriteCluster (Cluster: Int64; var Buffer; BufferSize: Longint): Boolean;

 Function WriteClusterChain(StartCluster: Longint; Buffer: Pointer; BufferSize: Longint): Boolean;

 Function ReadClusterChain(StartCluster: Int64; var Buffer: Pointer; var BufferSize: Longint): Boolean;

 Function SeekForChainStart(Cluster: Int64): Longint;

 Function ValidCluster (Cluster: Int64): Boolean;

 function ReadDIR(Cluster: Longint; var DIR: PDIR_Entry; var Entries: Longint): Boolean;

 Procedure Done;

  // Дополнение...

 procedure ParseDOSTime (Time: Word; var Hour, Minute, Second: Word);

 procedure ParseDOSDate (Date: Word; var Day, Month, Year: Word);

 function GetShortName (Name: String): String;

 function FormatDiskSize (Value: TLargeInteger): string;

 function DosToWin(St: string): string;

implementation



function ReadDIR(Cluster: Longint; var DIR: PDIR_Entry; var Entries: Longint): Boolean;

label

  Sector,

  LongNameComponent,

  ElementNotUsed,

  EndDIR;

var P: Pointer;

  P1: PDIREntry;

  PL: PLONGDIRENTRY;

  Dir_Entry: TDIR_Entry;

  Size: Longint;

  ADIR: TMemoryStream;

  J: DWORD;

  s,s1,sTmp: String;

  L:DWORD;

  LFNErase:Boolean;

begin

  s1:='';

  LFNErase:=False;

  Entries:=0;

  Result := False;

  if FSType = fsNone then Exit;

  if FAT = NIL then Exit;

  if FATSize = 0 then Exit;

  // Читаем ципочку кластеров в FAT пока не встретим $FFF

  Result := ReadClusterChain(Cluster, P, Size);

  // проверим нет ли ошибки с диском

  if not Result then Exit;

  // установим количество каталогов

  Size := Size div 32;

  // создаем поточный объект в памяти

  ADIR := TMemoryStream.Create;

  // P = начало каталога

  P1 := P;

 Sector:

  s:='';

  FillChar(DIR_Entry, SizeOf(DIR_Entry), 0);

  // Проверить признак конца каталога

  if (Byte(Pointer(Longint(P1)+$00)^) = $00) then

// if (Byte(Pointer(Longint(P1)+$0B)^) = $00) then

  goto EndDir;

  // Проверить наличие данных в элементе каталга

  if Byte(Pointer(P1)^) = $e5 then

  DIR_Entry.Erased := True else

  DIR_Entry.Erased := False;

  // Обычный элемент или компонента длинного имени?

  if (Byte(Pointer(Longint(P1)+$0b)^) = $0F) then

  Begin

  Inc(Longint(P1), SizeOf(TDIRENTRY));

  Goto Sector;

  end;

{ if ((Byte(Pointer(P1)^) and $3F) = 37) then

  Begin

  Inc(Longint(P1), SizeOf(TDIRENTRY));

  Goto Sector;

  end

  else

  Goto LongNameComponent;}


  // Проверить признак метки если "True" пропустим его...

  if Byte(Pointer(Longint(P1)+$0b)^) = ATTR_VOLUME then

  Begin

  Inc(Longint(P1), SizeOf(TDIRENTRY));

  Goto Sector;

  end;

  Begin

  // Обрабатываем короткое имя

  if ((Byte(Pointer(Longint(P1)+$0b)^) and ATTR_DIRECTORY) = 0) and

  (P1^.Ext[1] <> chr($20))then

  s:=P1^.Name+'.'+P1^.Ext else

  s:=P1^.Name;

  for j:=1 to Length(s) do

  if (s[j] <> chr($20)) then

  Dir_Entry.Name:=Dir_Entry.Name+s[j];

  for j:=1 to 3 do

  Dir_Entry.Ext:=Dir_Entry.Ext+P1^.Ext[j];

  s:='';

  end;

  Goto ElementNotUsed;

 LongNameComponent:

  PL:=PLONGDIRENTRY(P1);

  if (PL.LFN1[1] <> WideChar(0)) and (PL.LFN1[1] <> WideChar($FFFF)) then

  For j:=1 to 5 do if (PL.LFN1[j] <> #0) then s:=s+PL.LFN1[j];

  if (PL.LFN2[1] <> WideChar(0)) and (PL.LFN2[1] <> WideChar($FFFF)) then

  For j:=1 to 6 do if (PL.LFN2[j] <> #0) then s:=s+PL.LFN2[j];

  if (PL.LFN3[1] <> WideChar(0)) and (PL.LFN3[1] <> WideChar($FFFF)) then

  For j:=1 to 2 do if (PL.LFN3[j] <> #0) then s:=s+PL.LFN3[j];

  s1:=s+s1;



  if ((Byte(Pointer(P1)^) and $3F) <> 01) then

  Begin

  Inc(Longint(P1), SizeOf(TDIRENTRY));

  Goto Sector;

  end;

  Inc(Longint(P1), SizeOf(TDIRENTRY));

  Dir_Entry.Name:=s1;

  LFNErase:=False;

  s1:='';

  s:='';

 ElementNotUsed:

  // Сохраним текущий сектор и смещение текущего элемента

  // Он будет нужен в будущем...

  Dir_Entry.CurrentSector:=(LongInt(P1)-LongInt(P)) div 512;

  l:=(LongInt(P1)-LongInt(P));

  l:=l-(512*Dir_Entry.CurrentSector);

  Dir_Entry.StartByteNamePerSec:=l;

  if Cluster <> 0 then

  Dir_Entry.CurrentSector:=Dir_Entry.CurrentSector+((Cluster-2)*

  SectorsPerCluster)+DataAreaSector else

  Dir_Entry.CurrentSector:=Dir_Entry.CurrentSector+RootDirSector;

  DIR_Entry.Attr := P1^.Attr;

  if FSType = fsFAT32 then

  begin

  DIR_Entry.StartCluster := P1^.FSIClasHi;

  DIR_Entry.StartCluster := DIR_Entry.StartCluster shl 16;

  DIR_Entry.StartCluster := DIR_Entry.StartCluster+P1^.FSIClasLo;

  end else

  DIR_Entry.StartCluster := P1^.FSIClasLo;

  DIR_Entry.CreateTime := P1^.CrtTime;

  DIR_Entry.CreateDate := P1^.CrtDate;

  DIR_Entry.FileSize := P1^.Size;

  DIR_Entry.LastAccessDate := P1^.LstAccDate;

  DIR_Entry.WriteLastTime := P1^.WrtTime;

  DIR_Entry.WriteLastDate := P1^.WrtDate;

  Inc(Longint(P1), SizeOf(TDIRENTRY));

  ADIR.Write(DIR_Entry, SizeOf(DIR_Entry));

  inc(Entries);

 Goto Sector;

 EndDir:

  FreeMem(P);

  GetMem(DIR, ADIR.Size);

  ADIR.Seek(0, 0);

  ADIR.Read(DIR^, ADIR.Size);

  ADIR.Free;

  Result := True;

end;



 function ReadSector (Sector: Int64; Count: Word; Var Buffer; nSize:DWORD): Boolean;

 Var

  F:TMemoryStream;

  P:Pointer;

 Begin

  FillChar(Buffer, nSize, 0);

  Result:=False;

  if Volume = 0 Then Exit;

  F := TMemoryStream.Create;

  F.SetSize(Count*BytesPerSector);

  P:=F.Memory;

  Result:=ReadLogicalSector(Volume, Sector, Count,P^);

  F.Seek(0, 0);

  if nSize > F.Size then

  F.Read(Buffer, F.Size) else

  F.Read(Buffer, nSize);

  F.Free;

 end;

 function WriteSector (Sector: Int64; Count: Word; Var Buffer; nSize:DWORD): Boolean;

 Var

  F:TMemoryStream;

  P:Pointer;

 Begin

  Result:=False;

  if Volume = 0 Then Exit;

  F := TMemoryStream.Create;

  F.SetSize(Count*BytesPerSector);

  F.Seek(0, 0);

  F.Write(Buffer, F.Size);

  P := F.Memory;

  Result:=WriteLogicalSector(Volume, Sector, Count, P^);

  F.Seek(0, 0);

  if nSize > F.Size then F.Read(Buffer, F.Size)

  else F.Read(Buffer, nSize);

  F.Free;

 end;

 function GetFATCluster(FATIndex: LongInt): LongInt;

 begin

  Result := 0;

  if FATCount=0 then Exit;

  if FATIndex<1 then FATIndex := 1;

  if FATIndex>FATCount then FATIndex := FATCount;

  Result := Longint(Pointer(Longint(FATSector)+(FATIndex-1)*4)^);

 end;

 Function Init(Drive:byte):Boolean;

 Var

  NumFreeClusters : DWORD; // количество свободных кластеров на диске

  TotalClusters : DWORD; // Количество кластеров}

 var

  P, P1, P2: Pointer;

  I, J: Longint;

  B1, B2: Byte;

  W: Word;

  L: Longint;

 Begin

 Result:=False;

 Volume := Drive;

 GetDiskFreeSpace(PChar(chr(drive+64)+':\'), SectorsPerCluster,BytesPerSector, NumFreeClusters, TotalClusters);

 GetMem(P, BytesPerSector);

 if not ReadLogicalSector(Volume,0,1,P^) then

 begin

  FreeMem(P);

  Exit;

 end;

 if PBoot32(P)^.bsFATz16 = 0 Then

 with PBoot32(P)^ do

 Begin

  for I := 1 to 8 do FSName[I] := bsFSType[I];

  for I := 1 to 11 do VolumeName[I] := bsVolLab[I];

  FSType := fsFAT32;

  VolumeSerial := bsVolID;

  PhysicalVolume := bsDrvNum;

  LogicalSectors := bsTolSec32;

  SectorsPerCluster := bsSecPerClus;

  BytesPerSector := bsBytePerSec;

  FATCount := bsNumFATs;

  GetMem(FATSector, FATCount*4);

  SectorsPerFAT := bsFATSz32;

  I := bsRsvdSecCnt;

  If bsExtFlags and (1 shl 7) <> 0 Then

  ActiveFAT := bsExtFlags and $F;

  RootDirCluster := bsRootClus;

  DataAreaSector := bsRsvdSecCnt + FATCount * SectorsPerFAT;

  RootDirSector := DataAreaSector + (RootDirCluster-2) * SectorsPerCluster;

 end else

 Begin

  with PBoot(P)^ do

  Begin

  for I := 1 to 8 do FSName[I] := bsFSType[I];

  for I := 1 to 11 do VolumeName[I] := bsVolLab[I];

  if (TotalClusters > 4086) or (bsToolSec12 = 0) then

  Begin

  FSType := fsFAT16;

  LogicalSectors := bsToolSec16;

  end else

  Begin

  FSType := fsFAT12;

  LogicalSectors := bsToolSec12;

  end;

  VolumeSerial := bsVolID;

  PhysicalVolume := bsDrvNum;

  SectorsPerCluster := bsSecPerClus;

  BytesPerSector := bsBytePerSec;

  FATCount := bsNumFATs;

  GetMem(FATSector, FATCount*4);

  SectorsPerFAT := bsFATSz16;

  I := bsRsvdSecCnt;

  ActiveFAT := 0;

  RootDirEntries := bsRootEntCnt;

  RootDirSector := bsRsvdSecCnt+SectorsPerFAT*FATCount;

  RootDirCluster := 0;

  DataAreaSector := RootDirSector+((RootDirEntries*32+BytesPerSector-1) div BytesPerSector);

  end;

 end;

  // Заполняем адреса файловых структур 1/2

  // в FATSector

  Longint(FATSector^) := I;

  P1 := FATSector;

  Inc(Longint(P1), 4);

  if FATCount>1 then

  for J := 2 to FATCount do

  begin

  I := I+SectorsPerFAT;

  Longint(P1^) := I;

  Inc(Longint(P1), 4);

  end;

  dsBytePerSector:=BytesPerSector;

  EndingCluster :=((LogicalSectors-DataAreaSector) div SectorsPerCluster)+1;

  FreeMem(P);

  if FSType = fsNone then Exit;

  GetMem(P, SectorsPerFAT*FATCount*BytesPerSector);

  if not ReadSector(GetFATCluster(1), SectorsPerFAT*FATCount,

  P^, SectorsPerFAT*FATCount*BytesPerSector) then

  begin

  FreeMem(P);

  Exit;

  end;

  FATSize := EndingCluster-1;

  GetMem(FAT, FATSize*FATCount*4);

  FillChar(FAT^, FATSize*FATCount*4, 0);

  P2:= FAT;

  if FSType = fsFAT12 then

  begin

  for J := 0 to FATCount-1 do

  begin

  P1 := Pointer(Longint(P)+J*SectorsPerFAT*BytesPerSector+3);

  for I := 1 to FATSize div 2 do

  begin

  B1 := Byte(P1^); Inc(Longint(P1));

  B2 := Byte(P1^) and $0F;

  W := B2; W := (W shl 8) or B1;

  L := W;

  Longint(P2^) := L and FAT_MASK_12;

  Inc(Longint(P2), 4);

  B1 := Byte(P1^) and $F0; Inc(Longint(P1));

  B2 := Byte(P1^); Inc(Longint(P1));

  W := B2; W := (W shl 4) or (B1 shr 4);

  L := W;

  Longint(P2^) := L and FAT_MASK_12;

  Inc(Longint(P2), 4);

  end;

  if Odd(FATSize) then

  begin

  B1 := Byte(P1^); Inc(Longint(P1));

  B2 := Byte(P1^) and $0F;

  W := B2; W := (W shl 8) or B1;

  L := W;

  Longint(P2^) := L and FAT_MASK_12;

  end;

  end;

  end else

  if FSType = fsFAT16 then

  begin

  for J := 0 to FATCount-1 do

  begin

  P1 := Pointer(Longint(P)+J*SectorsPerFAT*BytesPerSector+4);

  for I := 1 to FATSize do

  begin

  L := Word(P1^); Inc(Longint(P1), 2);

  Longint(P2^) := L and FAT_MASK_16;

  Inc(Longint(P2), 4);

  end;

  end;

  end else

  if FSType = fsFAT32 then

  begin

  for J := 0 to FATCount-1 do

  begin

  P1 := Pointer(Longint(P)+J*SectorsPerFAT*BytesPerSector+8);

  for I := 1 to FATSize do

  begin

  L := Longint(P1^);

  Inc(Longint(P1), 4);

  Longint(P2^) := L and FAT_MASK_32;

  Inc(Longint(P2), 4);

  end;

  end;

  end;

  FreeMem(P);

end;



function GetFATEntry(Cluster: Int64): Longint;

Var

 CopyOfFAT:Byte;

begin

  Result := -1;

  if FSType = fsNone then Exit;

  if FAT = NIL then Exit;

  if FATSize = 0 then Exit;

  if ActiveFAT = 0 then

  CopyOfFAT := FATCount else

  CopyOfFAT := ActiveFAT;

  Cluster := Cluster-2;

  CopyOfFAT := CopyOfFAT-1;

  Result := Longint(Pointer(Longint(FAT)+CopyOfFAT*FATSize*4+Cluster*4)^);

  if FSType = fsFAT12 then Result := Result and FAT_MASK_12 else

  if FSType = fsFAT16 then Result := Result and FAT_MASK_16 else

  Result := Result and FAT_MASK_32;

end;

procedure SetFATEntry(Cluster: Int64; Value: Longint);

Var

 CopyOfFAT:Byte;

begin

  if FSType = fsNone then Exit;

  if FAT = NIL then Exit;

  if FATSize = 0 then Exit;

  if ActiveFAT = 0 then CopyOfFAT := FATCount else

  CopyOfFAT := ActiveFAT;

// if Cluster < 2 then Cluster := 2;

// if Cluster > EndingCluster then Cluster := EndingCluster;

  Cluster := Cluster-2;

  CopyOfFAT := CopyOfFAT-1;

  if FSType = fsFAT12 then Value := Value and FAT_MASK_12 else

  if FSType = fsFAT16 then Value := Value and FAT_MASK_16 else

  Value := Value and FAT_MASK_32;

  Longint(Pointer(Longint(FAT)+CopyOfFAT*FATSize*4+Cluster*4)^) := Value;

end;



FUNCTION GetCluster(Sector: Int64):Int64;

BEGIN

  if (Sector - DataAreaSector >= 0) and (LogicalSectors -Sector >= 0) then

  GetCluster :=(Sector-DataAreaSector) div SectorsPerCluster

  else

  Result := 0;

END;

function ReadCluster(Cluster: Int64; var Buffer; BufferSize: Longint): Boolean;

var P: Pointer;

  I: Int64;

begin

  Result := False;

  if Cluster < 1 then Cluster := RootDirCluster;

  Cluster := Cluster-2;

  GetMem(P, BytesPerSector*SectorsPerCluster);

  I := DataAreaSector + (SectorsPerCluster*Cluster);

  Result := ReadSector(I, SectorsPerCluster, Buffer,

  BytesPerSector*SectorsPerCluster);

  FreeMem(P);

end;

function WriteCluster(Cluster: Int64; var Buffer; BufferSize: Longint): Boolean;

var P: Pointer;

  I: Int64;

begin

  Result := False;

  if FSType = fsNone then Exit;

  if FATSize = 0 then Exit;

  if Cluster < 1 then Cluster := RootDirCluster;

  Cluster := Cluster-2;

  GetMem(P, BytesPerSector*SectorsPerCluster);

  FillChar(P^, BytesPerSector*SectorsPerCluster, 0);

  if BufferSize > BytesPerSector * SectorsPerCluster then

  BufferSize := BytesPerSector*SectorsPerCluster;

  Move(Buffer, P^, BufferSize);

  I := DataAreaSector+SectorsPerCluster*Cluster;

  Result := WriteSector(I, SectorsPerCluster, P^,

  BytesPerSector*SectorsPerCluster);

  FreeMem(P);

end;



function WriteClusterChain(StartCluster: Longint; Buffer: Pointer; BufferSize: Longint): Boolean;

var ClusterSize: Longint;

  I: Int64;

begin

  Result := False;

  if FSType = fsNone then Exit;

  if FAT = NIL then Exit;

  if FATSize = 0 then Exit;

  if StartCluster < 1 then StartCluster := RootDirSector;

  ClusterSize := BytesPerSector*SectorsPerCluster;

  I := StartCluster;

  while ValidCluster(I) do

  begin

  if BufferSize<ClusterSize then

  begin

  Result := WriteCluster(I, Buffer^, BufferSize);

  Break;

  end else Result := WriteCluster(I, Buffer^, ClusterSize);

  if not Result then Break;

  Longint(Buffer) := Longint(Buffer)+ClusterSize;

  BufferSize := BufferSize-ClusterSize;

  I := GetFATEntry(I);

  end;

end;

function ReadClusterChain(StartCluster: Int64; var Buffer: Pointer; var BufferSize: Longint): Boolean;

var I, J:Int64;

  P: Pointer;

  F: TMemoryStream;

  B: Boolean;

begin

  Result := False;

  if FSType = fsNone then Exit;

  if FAT = NIL then Exit;

  if FATSize = 0 then Exit;

  if StartCluster < 1 then StartCluster := RootDirCluster;

  I := StartCluster;

  J := BytesPerSector*SectorsPerCluster;

  GetMem(P, J);

  F := TMemoryStream.Create;

  repeat

  if not ValidCluster(I) then Break;

  B := ReadCluster(I, P^, J);

  if not B then

  begin

  Result := False;

  Break;

  end;

  Result := True;

  F.Write(P^, J);

  I := GetFATEntry(I);

  until False;

  FreeMem(P);

  Buffer := NIL;

  BufferSize := 0;

  if Result then

  begin

  BufferSize := F.Size;

  GetMem(Buffer, BufferSize);

  F.Seek(0, 0);

  F.Read(Buffer^, BufferSize);

  end;

  F.Free;

end;

function SeekForChainStart(Cluster: Int64): Longint;

var I: DWORD;

  J:LongInt;

  B: Boolean;

begin

  Result := -1;

  if FSType = fsNone then Exit;

  if FAT = NIL then Exit;

  if FATSize = 0 then Exit;

  if Cluster < 1 then Cluster := RootDirCluster;

  J := -1;

  repeat

  B := False;

  for I := 2 to EndingCluster do

  if GetFATEntry(I) = Cluster then

  begin

  J := I;

  Cluster := I;

  B := True;

  Break;

  end;

  until not B;

  Result := J;

end;



function ValidCluster(Cluster: Int64): Boolean;

begin

  Result := (Cluster>=2) and (Cluster<=EndingCluster);

end;







Procedure Done;

Begin

  if FATSector <> NIL then FreeMem(FATSector);

  if FAT <> NIL then FreeMem(FAT);

end;



(******************************************************************************)

procedure ParseDOSTime(Time: Word; var Hour, Minute, Second: Word);

begin

 Second := (Time and $001f)*2;

 Minute := (Time and $07e0) shr 5;

 Hour := (Time and $f800) shr 11;

end;

procedure ParseDOSDate(Date: Word; var Day, Month, Year: Word);

begin

 Day := Date and $001f;

 Month := (Date and $01e0) shr 5;

 Year := ((Date and $fe00) shr 9) + 1980;

end;



function GetShortName(Name: String): String;

var S: String;

  I: Longint;

begin

  SetLength(S, 10000);

  I := GetShortPathName(PChar(Name), @S[1], 10000);

  SetLength(S, I);

  Result := S;

end;



function FormatDiskSize (Value: TLargeInteger): string;

const

 SizeUnits: array[1..5] of string = (' Bytes', ' KB', ' MB', ' GB', 'TB');

var

 SizeUnit: Integer;

 Temp: TLargeInteger;

 Size: Integer;

begin

 SizeUnit := 1;

 if Value < 1024 then

  Result := IntToStr(Value)

 else begin

  Temp := Value;

  while (Temp >= 1000*1024) and (SizeUnit <= 5) do begin

  Temp := Temp shr 10; //div 1024

  Inc(SizeUnit);

  end;

  Inc(SizeUnit);

  Size := (Temp shr 10); //div 1024

  Temp := Temp - (Size shl 10);

  if Temp > 1000 then

  Temp := 999;

  if Size > 100 then

  Result := IntToStr(Size)

  else if Size > 10 then

  Result := Format('%d%s%.1d', [Size, DecimalSeparator, Temp div 100])

  else

  Result := Format('%d%s%.2d', [Size, DecimalSeparator,

  Temp div 10])

 end;

 Result := Result + SizeUnits[SizeUnit];

end;



function DosToWin(St: string): string;

var

 Ch: PChar;

begin

 Ch := StrAlloc(Length(St) + 1);

 OemToAnsi(PChar(St), Ch);

 Result := Ch;

 StrDispose(Ch)

end;



end.

unit uFAT; erface # наверное тут всётаки interface должно быть

Uses Windows,SysUtils,DISK,CLASSES; # CLASSES --> Classes

DISK, эт что за левый модуль и где его брать?

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...