Модуль для работы с дисковыми драйверами (На уровне секторов)
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.