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

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

{ Автор : NikNet
 MAIL : NikNet@yandex.ru}

Unit Disk;
Interface
Uses Windows,SysUtils;
VAR
 dsBytePerSector : word = 512; // Установите размер сектора
function ReadLogicalSector (Drive: Byte; Sector: Int64; Count: Word; Var Buffer): Boolean;
function WriteLogicalSector (Drive: Byte; Sector: Int64; Count: Word; Var Buffer): Boolean;
function ReadPlysicalSector (HddNumber: Byte; Sector:Int64; Count:word; Var Buffer): DWORD;
function WritePlysicalSector(HddNumber: Byte; Sector:Int64; Count:word; Var Buffer): DWORD;

Implementation

 TYPE
  PDIOC_Registers = ^TDIOC_Registers;
  TDIOC_Registers = record
  case Byte of
  0: (EBX,EDX,ECX,EAX,EDI,ESI,Flags: DWord);
  1: (BX,BXE,DX,DXE,CX,CXE,AX,AXE,DI,DIE,SI,SIE: Word);
  end;
 TReadWritePacket = packed record
  StartSector: DWord;
  Sectors : Word;
  Buffer : Pointer;
 end;
const
 VWIN32_DEVICE_NAME  = '\\.\VWIN32';
 VWIN32_DIOC_CLOSE = 0; { Close the device. }
 VWIN32_DIOC_DOS_IOCTL = 1; { MS-DOS device I/O control function, }
  { interrupt 21h function 4400h through 4411h }
 VWIN32_DIOC_DOS_INT25 = 2; { MS-DOS absolute disk read command, }
  { interrupt 25h. }
 VWIN32_DIOC_DOS_INT26 = 3; { MS-DOS absolute disk write command, }
  { interrupt 26h. }
 VWIN32_DIOC_DOS_INT13 = 4; { Low-level BIOS disk functions, }
  { interrupt 13h. }
 VWIN32_DIOC_DOS_DRIVEINFO = 6; { MS-DOS Interrupt 21h new function 730x. }
  { Supported only by Windows 95 OSR2 and later.}
 FLAG_CARRY = $00000001;
 // Error codes
 ERROR_NON = $0000; { no error }
 // MS-DOS/Windows error codes:
 ERROR_INVALID_FUNCTION  = $0001; { invalid function number }
 ERROR_FILE_NOT_FOUND = $0002; { file not found }
 ERROR_ACCESS_DENIED = $0005; { specified access denied on drive }
 ERROR_INVALID_DRIVE = $000F; { invalid drive number }
 ERROR_MEDIA_NOT_LOCKED = $00B0; { media is not locked in drive }
 ERROR_MEDIA_LOCKED = $00B1; { media is locked in drive }
 ERROR_MEDIA_NOT_REMOVABLE = $00B2; { media is not removable }
 ERROR_LOCKE_COUNT_EXCEEDED = $00B4; { media locke count exceeded }
 ERROR_EJECT_REQUEST_FAILED = $00B5; { valid media eject request failed }
 // Interrupt 13h/25h/26h error codes:
 ERROR_BAD_COMMAND = $10001; { bad command }
 ERROR_BAD_ADDRESS_MARK = $10002; { bad address mark }
 ERROR_WRITE_PROTECTED  = $10003; { write-protected disk }
 ERROR_SECTOR_NOT_FOUND = $10004; { requested sector not found }
 ERROR_RESET_FAILED = $10005; { reset failed }
 ERROR_DISK_CHANGED = $10006; { disk changed (floppy disk) }
 ERROR_PARAMETER_FAILED = $10007; { drive parameter activity failed }
 ERROR_DMA_FAILURE = $10008; { DMA failure/overrun }
 ERROR_DMA_SEGMENT_FAULT = $10009; { attempted DMA across 64K boundary }
 ERROR_BAD_SECTOR_DETECTED = $1000A; { bad sector detected }
 ERROR_BAD_TRACK_DETECTED = $1000B; { bad track detected }
 ERROR_INVALID_MEDIA = $1000C; { invalid media or unsupported track }
 ERROR_INVALID_SECTORS = $1000D; { invalid number of sectors on format }
 ERROR_CONTROL_DATA = $1000E; { control data address mark detected }
 ERROR_DMA_ARBITRATION = $1000F; { DMA arbitration level out of range }
 ERROR_DATA_ERROR = $10010; { data error (uncorrectable CRC or ECC) }
 ERROR_DATA_ECC_CORRECTED = $10011; { data ECC corrected }
 ERROR_CONTROLLER_FAILED = $10020; { controller failed }
 ERROR_SEEK_FAILED = $10040; { seek operation failed }
 ERROR_DEVICE_FAILED = $10080; { device failed to respond (timeout) }
 ERROR_DRIVE_NOT_READY = $100AA; { drive not ready }
 ERROR_UNDEFINED = $100BB; { undefined error }
 ERROR_WRITE_FAULT = $100CC; { write fault }
 ERROR_STATUS_REGISTER  = $100E0; { status register error }
 ERROR_SENSE_FAILED = $100FF; { sense operation failed }
 // VWIN32 custom error codes:
 ERROR_UNKNOWN = $00100000; { unknown error }
 ERROR_OPENING_DEVICE = $00300000; { error trying to open device }
 { Lock permission codes: }
 LOCK_ALLOW_WRITING = $0001; { Allow write operations in level 1 lock. Write }
  { operations are always blocked in level 2 & 3 }
  { lock. }
 LOCK_BLOCK_MAPPING = $0002; { Block new file mappings in level 1 & 2 lock. }
  { New file mappings are always blocked in level }
  { 3 lock. }
  { Read operations are always allowed in level }
  { 1 & 2 lock, and blocked in level 3 lock. }
 LOCK_FOR_FORMATTING = $0004; { Locks the volume for formatting. Specified }
  { when a level 0 lock is obtained for the second}
  { time. }
Var
 VWIN32Error: DWord;
 VWIN32Device : THandle;

function VWIN32DIOC(ControlCode: Integer; Registers: PDIOC_Registers): Boolean;
var
 BytesReturned : DWord;
 function OpenDevice: Boolean;
 begin
  VWIN32Error := ERROR_NON;
  if (VWIN32Device = INVALID_HANDLE_VALUE) or (VWIN32Device = 0) then
  begin
  VWIN32Device := CreateFile(VWIN32_DEVICE_NAME,0,0,nil,0,FILE_FLAG_DELETE_ON_CLOSE,0);
  if (VWIN32Device = INVALID_HANDLE_VALUE) then
  VWIN32Error := ERROR_OPENING_DEVICE;
  end;
  Result := VWIN32Error = ERROR_NON;
 end;
 procedure CloseDevice;
 begin
  if (VWIN32Device <> INVALID_HANDLE_VALUE) then CloseHandle(VWIN32Device);
  VWIN32Device := INVALID_HANDLE_VALUE;
  Result := true;
 end;
begin
 VWIN32Error := ERROR_NON;
 if ControlCode = VWIN32_DIOC_CLOSE then CloseDevice
 else if OpenDevice then begin
  Result := DeviceIoControl(VWIN32Device,ControlCode,Registers,SizeOf(Registers^),
  Registers,SizeOf(Registers^),BytesReturned,nil);
  if not result then VWIN32Error := ERROR_UNKNOWN;
 end
 else Result := false;
end;

function LockLogicalVolume(Drive: Byte; Level, Permission: Byte): Boolean;
var
 Registers: TDIOC_Registers;
begin
 VWIN32Error := ERROR_NON;
 Result := false;
 if (Level > 1) then Permission := $00
 else Permission := Permission and $07;
  Registers.EAX := $440D;
  Registers.EBX := (Level shl 8) or Drive;
  Registers.ECX := $484A;
  Registers.EDX := Permission;
  Registers.Flags := $00000000;
  if (VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers)) then
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true;
 if not Result then
 begin
  Registers.EAX := $440D;
  Registers.EBX := (Level shl 8) or Drive;
  Registers.ECX := $084A;
  Registers.EDX := Permission;
  Registers.Flags := $00000000;
  if (VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers)) then begin
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true
  else VWIN32Error := Registers.AX;
  end;
 end;
end;
function UnlockLogicalVolume(Drive: Byte): Boolean;
var
 Registers: TDIOC_Registers;
begin
 VWIN32Error := ERROR_NON;
 Result := false;
  Registers.EAX := $440D;
  Registers.EBX := Drive;
  Registers.ECX := $486A;
  Registers.Flags := $00000000;
  if (VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers)) then
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true;
 if not Result then
 begin
  Registers.EAX := $440D;
  Registers.EBX := Drive;
  Registers.ECX := $086A;
  Registers.Flags := $00000000;
  if (VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers)) then
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true
  else VWIN32Error := Registers.AX;
 end;
end;

function ReadHDD9x(HDD: Byte; Sector: DWord; Count: Word; Var Buffer): Boolean;
TYPE
 TPacket = packed record
  PacketSize : Byte;
  Unesed1 : Byte;
  NumSector : Byte;
  Unesed2 : Byte;
  Buffer : POINTER;
  Sector : comp;
 end;
var
 Registers : TDIOC_Registers;
 Packet : TPacket;
begin
 Packet.PacketSize := 16  ; Packet.Unesed1 := 0;
 Packet.NumSector := Count ; Packet.Unesed2 := 0;
 Packet.Buffer := @Buffer ; Packet.Sector := Sector;
 VWIN32Error := ERROR_NON;
 Result := false;
 Registers.EAX := $4200; // Read one sector
 Registers.ECX := $0000; // Cyl 0; Sec 1
 Registers.EDX := $0080; // Head 0; Dev. Num 80h ( HDD0 )
 Registers.ESI := DWORD(@Buffer); // Set ES:BX to Buffer
 VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers);
end;

function Read9xSector(Drive: Byte; Sector: DWord; Count: Word; Var Buffer): Boolean;
var
 Registers : TDIOC_Registers;
 ReadWritePacket : TReadWritePacket;
begin
 VWIN32Error := ERROR_NON;
 Result := false;
  ReadWritePacket.StartSector := Sector;
  ReadWritePacket.Sectors := Count;
  ReadWritePacket.Buffer := @Buffer;
  Registers.EAX := $7305;
  Registers.EBX := DWord(@ReadWritePacket);
  Registers.ECX := $FFFFFFFF;
  Registers.EDX := Drive;
  Registers.ESI := $0000;
  Registers.Flags := $00000000;
  if VWIN32DIOC(VWIN32_DIOC_DOS_DRIVEINFO,@Registers) then
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true;
 if (not Result) then
 begin
  ReadWritePacket.StartSector := Sector;
  ReadWritePacket.Sectors := Count;
  ReadWritePacket.Buffer := @Buffer;
  Registers.EAX := Drive-1;
  Registers.EBX := DWord(@ReadWritePacket);
  Registers.ECX := $FFFFFFFF;
  Registers.Flags := $00000000;
  if VWIN32DIOC(VWIN32_DIOC_DOS_INT25,@Registers) then begin
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true
  else VWIN32Error := $10000 or (Registers.AX and $00FF);
  end;
 end;
end;

function Write9xSector(Drive: Byte; Sector: DWord; Count: Word; Var Buffer; Mode: Byte): Boolean;
var
 Registers : TDIOC_Registers;
 ReadWritePacket: TReadWritePacket;
begin
 VWIN32Error := ERROR_NON;
 Result := false;
 if (LockLogicalVolume(Drive, 1, LOCK_ALLOW_WRITING)) then
 begin
  ReadWritePacket.StartSector := Sector;
  ReadWritePacket.Sectors := Count;
  ReadWritePacket.Buffer := @Buffer;
  Registers.EAX := $7305;
  Registers.EBX := DWord(@ReadWritePacket);
  Registers.ECX := $FFFFFFFF;
  Registers.EDX := Drive;
  Registers.ESI := $0001 or (Mode and $6000);
  Registers.Flags := $00000000;
  if (VWIN32DIOC(VWIN32_DIOC_DOS_DRIVEINFO,@Registers)) then
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true;
  if (not Result) then
  begin
  ReadWritePacket.StartSector := Sector;
  ReadWritePacket.Sectors := Count;
  ReadWritePacket.Buffer := @Buffer;
  Registers.EAX := Drive-1;
  Registers.EBX := DWord(@ReadWritePacket);
  Registers.ECX := $FFFFFFFF;
  Registers.Flags := $00000000;
  if (VWIN32DIOC(VWIN32_DIOC_DOS_INT26,@Registers)) then
  begin
  if ((Registers.Flags and FLAG_CARRY) = 0) then Result := true
  else VWIN32Error := $10000 or (Registers.AX and $00FF);
  end;
  end;
  UnlockLogicalVolume(Drive);
 end;
end;

function __Mul(a,b: DWORD; var HiDWORD: DWORD): DWORD; // Result = LoDWORD
asm
 mul edx
 mov [ecx],edx
end;

function ReadNTSector(Drive: Byte; Sector,SectorCount: DWord; Var Buffer): Boolean;
var
 hDrive: THandle;
 DriveRoot: string;
 br,TmpLo,TmpHi: DWORD;
begin
 Result := False;
 TmpLo:=0;
 TmpHi:=TmpLo;
 DriveRoot := '\\.\' + Chr(64 + Drive) + ':';
 hDrive := CreateFile(
  PAnsiChar(DriveRoot), GENERIC_READ,
  FILE_SHARE_READ or FILE_SHARE_WRITE,
  nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if (hDrive = INVALID_HANDLE_VALUE) then Exit;
  TmpLo :=__Mul(Sector,dsBytePerSector,TmpHi);
  if SetFilePointer(hdrive,TmpLo,@TmpHi,FILE_BEGIN) = TmpLo then
  begin
  if ReadFile(hdrive,Buffer,dsBytePerSector*SectorCount,br,nil) then
  Result := BR = (dsBytePerSector*SectorCount);
 end;
  CloseHandle(hDrive);
end;

function WriteNTSector(Drive: Byte; Sector,SectorCount: DWord; Var Buffer): Boolean;
var
 hDrive: THandle;
 DriveRoot: string;
 bw,TmpLo,TmpHi: DWORD;
begin
 Result := False;
 DriveRoot := '\\.\' + Chr(64 + Drive) + ':';
 hDrive := CreateFile(
  PAnsiChar(DriveRoot), GENERIC_WRITE,
  FILE_SHARE_READ or FILE_SHARE_WRITE,
  nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if (hDrive = INVALID_HANDLE_VALUE) then Exit;
 TmpLo :=__Mul(Sector,dsBytePerSector,TmpHi);
 if SetFilePointer(hdrive,TmpLo,@TmpHi,FILE_BEGIN) = TmpLo then
 begin
  if not WriteFile(hdrive,Buffer,dsBytePerSector*SectorCount,bw,nil) then Exit;
  Result := bw = (dsBytePerSector*SectorCount);
 end;
  CloseHandle(hDrive);
end;
function ReadLogicalSector (Drive: Byte; Sector: Int64; Count: Word; Var Buffer): Boolean;
begin
 case Win32Platform of
 VER_PLATFORM_WIN32_WINDOWS: Result:= Read9xSector(Drive, Sector, Count, Buffer);
 VER_PLATFORM_WIN32_NT : Result:= ReadNTSector(Drive, Sector, Count, Buffer);
 End;
end;
function WriteLogicalSector (Drive: Byte; Sector: Int64; Count: Word; Var Buffer): Boolean;
begin
 case Win32Platform of
 VER_PLATFORM_WIN32_WINDOWS: Result:= Write9xSector(Drive, Sector, Count, Buffer,1);
 VER_PLATFORM_WIN32_NT : Result:= WriteNTSector(Drive, Sector, Count, Buffer);
 End;
end;

function ReadPlysicalSector (HddNumber: Byte; Sector:Int64; Count:word; Var Buffer): DWORD;
var
 hFile: THandle;
 br,TmpLo,TmpHi: DWORD;
begin
 Result := 0;
 hFile := CreateFile(PChar('\\.\PhysicalDrive'+IntToStr(HddNumber)),
  GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
 if hFile = INVALID_HANDLE_VALUE then Exit;
 TmpLo := __Mul(Sector,dsBytePerSector,TmpHi);
 if SetFilePointer(hFile,TmpLo,@TmpHi,FILE_BEGIN) = TmpLo then
 begin
  Count := Count*dsBytePerSector;
  if ReadFile(hFile,Buffer,Count,br,nil) then Result := br;
 end;
 CloseHandle(hFile);
end;
function WritePlysicalSector (HddNumber: Byte; Sector:Int64; Count:word; Var Buffer): DWORD;
var
 hFile: THandle;
 bw,TmpLo,TmpHi: DWORD;
begin
 Result := 0;
 hFile := CreateFile(PChar('\\.\PhysicalDrive'+IntToStr(HddNumber)),
  GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
 if hFile = INVALID_HANDLE_VALUE then Exit;
 TmpLo := __Mul(Sector,dsBytePerSector,TmpHi);
 if SetFilePointer(hFile,TmpLo,@TmpHi,FILE_BEGIN) = TmpLo then
 begin
  Count := Count*dsBytePerSector;
  if WriteFile(hFile,Buffer,Count,bw,nil) then Result := bw;
 end;
 CloseHandle(hFile);
end;

 Function GetLogic(C,H,S,Hmax,Smax:Int64):comp;
 BEGIN
  GetLogic:=(C*Hmax+H)*Smax+S-1;
 END;

 Procedure GetPhysical(N,Hmax,Smax:Int64; var C,H,S:Int64);
 BEGIN
  C:=N div (Hmax*Smax);
  H:=(N-C*Hmax*Smax) div Smax;
  S:=N-(C*Hmax+H)*Smax+1;
 END;
 PROCEDURE UnPackCylSec(CSec:word; var Cyl,Sec: Word);
 Begin
  Cyl := (CSec and 192) shl 2+CSec shr 8;
  Sec := CSec and 63;
 end;
 FUNCTION PackCylSec(Cyl,Sec: Word): Word;
 BEGIN
  PackCylSec := Sec+(Cyl and $300) shr 2+(Cyl shl 8)
 END;

end.

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

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