Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОС_ЛР 942_Часть1.doc
Скачиваний:
16
Добавлен:
15.04.2015
Размер:
651.26 Кб
Скачать

1.3. Программная реализация чтения системных структур раздела диска с файловой системой fat 32

Обращение к разделу жесткого диска в операционных системах Windows 2000/XP может быть выполнено путем открытия диска как файла с помощью функции CreateFile и указания диска или его раздела по схеме Device Namespace (открывается физический диск - '\\.\PHYSICALDRIVE<n>'). Полученный хэндл в дальнейшем используется для работы с диском с помощью функций ReadFile, WriteFile и DeviceIoControl.

Для выполнения этой операции можно использовать следующий программный код:7

// Drive - номер диска (нумерация с нуля).

hFile := CreateFile(PChar('\\.\PhysicalDrive'+IntToStr(Drive)),

GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0);

if hFile = INVALID_HANDLE_VALUE then Exit;

В результате появляется возможность воспринимать физический диск как единый файл.

Чтобы получить информацию о геометрии диска можно использовать еще один программный фрагмент:

const

IOCTL_DISK_GET_DRIVE_GEOMETRY = $70000;

type

TDiskGeometry = packed record

Cylinders: Int64; // количество цилиндров

MediaType: DWORD; // тип носителя

TracksPerCylinder: DWORD; // дорожек на цилиндре

SectorsPerTrack: DWORD; // секторов на дорожке

BytesPerSector: DWORD; // байт в секторе

end;

Result := DeviceIoControl(hFile,IOCTL_DISK_GET_DRIVE_GEOMETRY,nil,0,

@DiskGeometry,SizeOf(TDiskGeometry),junk,nil) and (junk = SizeOf(TDiskGeometry));

Функция DeviceIoControl возвращает True, если операция прошла успешно, и False в противном случае.

Основной операцией при работе с системными структурами данных FAT32 является операция чтения содержимого сектора диска. Она может быть выполнена с помощью функции, одна из программных реализаций которых (функция ReadSectors) представлена ниже.

// так как диск - это единый файл, то для перемещения по нему

// с помощью функции SetFilePointer понадобится 64х-разрядная арифметика

function __Mul(a,b: DWORD; var HiDWORD: DWORD): DWORD; // Result = LoDWORD

asm

mul edx

mov [ecx],edx

end;

function ReadSectors(DriveNumber: Byte; StartingSector, SectorCount: DWORD;

Buffer: Pointer; BytesPerSector: DWORD = 512): DWORD;

var

hFile: THandle;

br,TmpLo,TmpHi: DWORD;

begin

Result := 0;

hFile := CreateFile(PChar('\\.\PhysicalDrive'+IntToStr(DriveNumber)),

GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

if hFile = INVALID_HANDLE_VALUE then Exit;

TmpLo := __Mul(StartingSector,BytesPerSector,TmpHi);

if SetFilePointer(hFile,TmpLo,@TmpHi,FILE_BEGIN) = TmpLo then

begin

SectorCount := SectorCount*BytesPerSector;

if ReadFile(hFile,Buffer^,SectorCount,br,nil) then Result := br;

end;

CloseHandle(hFile);

end;

Функция ReadSectors возвращает количество прочитанных байт.

Ниже в качестве примера приводится программный код для чтения сектора диска, содержащего структуры MBR и Partition Table.

TPartitionTableEntry = packed record

BootIndicator: Byte; // $80, если активный (загрузочный) раздел

StartingHead: Byte;

StartingCylAndSect: Word;

SystemIndicator: Byte;

EndingHead: Byte;

EndingCylAndSect: Word;

StartingSector: DWORD; // начальный сектор

NumberOfSects: DWORD; // количество секторов

end;

TPartitionTable = packed array [0..3] of TPartitionTableEntry;

PDriveInfo = ^TDriveInfo;

TDriveInfo = record

PartitionTable: TPartitionTable;

LogicalDrives: array [0..3] of PDriveInfo;

end;

const

PartitionTableOffset = $1be;

ExtendedPartitions = [5,$f];

var

MainExPartOffset: DWORD = 0;

function GetDriveInfo(DriveNumber: Byte; DriveInfo: PDriveInfo;

StartingSector: DWORD; BytesPerSector: DWORD = 512): Boolean;

var

buf: array of Byte;

CurExPartOffset: DWORD;

i: Integer;

begin

SetLength(buf,BytesPerSector);

// читаем сектор в буфер

if ReadSectors(DriveNumber,MainExPartOffset+StartingSector,1,@buf[0]) = 0 then

begin

Result := False;

Exit;

end;

// заполняем структуру DriveInfo.PartitionTable

Move(buf[PartitionTableOffset],DriveInfo.PartitionTable,SizeOf(TPartitionTable));

Finalize(buf); // буфер больше не нужен

Result := True;

for i := 0 to 3 do // для каждой записи в Partition Table

if DriveInfo.PartitionTable[i].SystemIndicator in ExtendedPartitions then

begin

New(DriveInfo.LogicalDrives[I]);

if MainExPartOffset = 0 then

begin

MainExPartOffset := DriveInfo.PartitionTable[I].StartingSector;

CurExPartOffset := 0;

end else CurExPartOffset := DriveInfo.PartitionTable[I].StartingSector;

Result := Result and GetDriveInfo(DriveNumber,DriveInfo.LogicalDrives[I],

CurExPartOffset);

end else DriveInfo.LogicalDrives[I] := nil;

end;

Функция GetDriveInfo заполняет структуру DriveInfo и возвращает True, если операция прошла успешно, или False в противном случае.