Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

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

01.01.2007
{ Автор : 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.