Prova a studiare questa. consente di scegliere in quale settore andare a scrivere e controlla la dimensione del cluster, poi fa un controllo che tutto sia andato a buon fine.
uses
Windows, SysUtils;
type
TDiskInfo = record
PhysicalPath: string;
BytesPerSector: DWORD;
PhysicalBytesPerSector: DWORD;
TotalSectors: Int64;
end;
function GetPhysicalDriveFromLetter(const DriveLetter: Char): string;
var
hVolume: THandle;
BytesReturned: DWORD;
Extents: VOLUME_DISK_EXTENTS;
begin
Result := '';
hVolume := CreateFile(PChar(Format('\\.\%s:', [UpCase(DriveLetter)])),
0, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if hVolume = INVALID_HANDLE_VALUE then Exit;
try
if DeviceIoControl(hVolume,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
nil, 0,
@Extents, SizeOf(Extents),
BytesReturned, nil) then
begin
Result := Format('\\.\PhysicalDrive%d',
[Extents.Extents[0].DiskNumber]);
end;
finally
CloseHandle(hVolume);
end;
end;
function GetDiskInfo(const PhysicalPath: string; out Info: TDiskInfo): Boolean;
var
hDevice: THandle;
BytesReturned: DWORD;
Geo: DISK_GEOMETRY_EX;
Query: STORAGE_PROPERTY_QUERY;
Desc: STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR;
begin
Result := False;
hDevice := CreateFile(PChar(PhysicalPath),
0, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if hDevice = INVALID_HANDLE_VALUE then Exit;
try
// Geometria base
if not DeviceIoControl(hDevice,
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
nil, 0,
@Geo, SizeOf(Geo),
BytesReturned, nil) then Exit;
Info.PhysicalPath := PhysicalPath;
Info.BytesPerSector := Geo.Geometry.BytesPerSector;
Info.TotalSectors := Geo.DiskSize.QuadPart div Info.BytesPerSector;
// Query settore fisico reale
ZeroMemory(@Query, SizeOf(Query));
Query.PropertyId := StorageAccessAlignmentProperty;
Query.QueryType := PropertyStandardQuery;
if DeviceIoControl(hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
@Query, SizeOf(Query),
@Desc, SizeOf(Desc),
BytesReturned, nil) then
begin
Info.PhysicalBytesPerSector := Desc.BytesPerPhysicalSector;
end
else
Info.PhysicalBytesPerSector := Info.BytesPerSector;
Result := True;
finally
CloseHandle(hDevice);
end;
end;
function IsSystemDisk(const PhysicalPath: string): Boolean;
begin
// controllo che non sia PhysicalDrive0
Result := Pos('PhysicalDrive0', PhysicalPath) > 0;
end;
function ValidateSector(const Info: TDiskInfo; Sector: Int64; out Err: string): Boolean;
begin
Result := False;
Err := '';
if Sector <= 0 then
begin
// controllo settore 0
Err := 'attenzione: settore 0 non consentito';
Exit;
end;
if Sector >= Info.TotalSectors then
begin
//controllo se il settore esiste
Err := 'Settore fuori range';
Exit;
end;
Result := True;
end;
function AllocAligned(Size, Align: Cardinal): Pointer;
var
Raw: Pointer;
Addr: UIntPtr;
begin
GetMem(Raw, Size + Align);
Addr := (UIntPtr(Raw) + Align - 1) and not (Align - 1);
Result := Pointer(Addr);
end;
function WriteSectorSafe(const Info: TDiskInfo; Sector: Int64): Boolean;
var
hDevice: THandle;
Offset: LARGE_INTEGER;
Buffer, VerifyBuffer, Backup: Pointer;
BytesRW: DWORD;
SectorSize: DWORD;
begin
Result := False;
SectorSize := Info.BytesPerSector;
Buffer := AllocAligned(SectorSize, Info.PhysicalBytesPerSector);
VerifyBuffer := AllocAligned(SectorSize, Info.PhysicalBytesPerSector);
Backup := AllocAligned(SectorSize, Info.PhysicalBytesPerSector);
try
FillChar(Buffer^, SectorSize, $AA);
hDevice := CreateFile(PChar(Info.PhysicalPath),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING or FILE_FLAG_WRITE_THROUGH,
0);
// usa esplicitamente le opzini FILE_FLAG_NO_BUFFERING or FILE_FLAG_WRITE_THROUGH,
if hDevice = INVALID_HANDLE_VALUE then Exit;
try
Offset.QuadPart := Sector * SectorSize;
SetFilePointerEx(hDevice, Offset, nil, FILE_BEGIN);
// BACKUP
if not ReadFile(hDevice, Backup^, SectorSize, BytesRW, nil) then Exit;
SetFilePointerEx(hDevice, Offset, nil, FILE_BEGIN);
// scrittura
if not WriteFile(hDevice, Buffer^, SectorSize, BytesRW, nil) then Exit;
SetFilePointerEx(hDevice, Offset, nil, FILE_BEGIN);
// verifica
if not ReadFile(hDevice, VerifyBuffer^, SectorSize, BytesRW, nil) then Exit;
if CompareMem(Buffer, VerifyBuffer, SectorSize) then
Result := True
else
begin
// ripristino
SetFilePointerEx(hDevice, Offset, nil, FILE_BEGIN);
WriteFile(hDevice, Backup^, SectorSize, BytesRW, nil);
end;
finally
CloseHandle(hDevice);
end;
finally
FreeMem(Buffer);
FreeMem(VerifyBuffer);
FreeMem(Backup);
end;
end;