The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Логическая структура жесткого диска


<< Предыдущая ИНДЕКС Правка src / Печать Следующая >>
Ключевые слова:  (найти похожие документы)
From: Bob <ubob@mail.ru.> Newsgroups: email Date: Mon, 24 Jan 2005 14:31:37 +0000 (UTC) Subject: Логическая структура жесткого диска Исправленный и переработанный вариант статьи доступен по адресу https://www.opennet.ru/base/dev/hdd_struct2.txt.html ЛОГИЧЕСКАЯ СТРУКТУРА ЖЕСТКОГО ДИСКА В статье расcматривается логическая структура жесткого диска, соответствующая стандарту Microsoft - "основной раздел - расширенный раздел - разделы не-DOS". Пространство на жестком диске может быть организовано в виде одного или нескольких разделов, а разделы могут содержать один или несколько логических дисков. На жестком диске по физическому адресу 0-0-1 располагается главная загрузочная запись (master boot record, MBR). В состав MBR входят: - внесистемный загрузчик (non-system bootstrap - NSB); - таблица описания разделов диска (таблица разделов, partition table, PT). Эта таблица расположена в MBR по смещению 0x1BE и занимает 64 байта; - сигнатура MBR. Последние два байта MBR должны содержать число 0xAA55. Таблица разделов описывает размещение и характеристики имеющихся на винчестере разделов. Разделы диска могут быть двух типов - primary (первичный, основной) и extended (расширенный). Максимальное число primary-разделов равно четырем. Наличие на диске хотя бы одного primary-раздела является обязательным. Extended-раздел может быть разделен на большое количество подразделов - логических дисков.Упрощенно структура MBR представлена в таблице 1. Таблица разделов располагается в конце MBR, для описания раздела в таблице отводится 16 байт. Таблица 1. Структура MBR Смещение (offset) Размер (Size) Содержимое (contents) ------------------------------------------------------------------------- 0 446 Программа анализа таблицы разделов и загрузки System Bootstrap с активного раздела ------------------------------------------------------------------------- 0x1BE 16 Partition 1 entry ( элемент таблицы разделов) ------------------------------------------------------------------------- 0x1CE 16 Partition 2 entry ------------------------------------------------------------------------- 0x1DE 16 Partition 3 entry ------------------------------------------------------------------------- 0x1EE 16 Partition 4 entry ------------------------------------------------------------------------- 0x1FE 2 Сигнатура 0xAA55 Структура записи элемента таблицы разделов показана в таблице 2. Таблица 2. Структура записи элемента таблицы разделов Смещение Размер поля, Содержание байт ------------------------------------------------------------------------- 0x00 1 Признак активности (0 - раздел не активный, 0x80 - раздел активный) -------------------------------------------------------------------------- 0x01 1 Номер головки диска, с которой начинается раздел --------------------------------------------------------------------------- 0x02 2 Номер цилиндра и номер сектора, с которых начинается раздел ---------------------------------------------------------------------------- 0x04 1 Код типа раздела System ID ---------------------------------------------------------------------------- 0x05 1 Номер головки диска, на которой заканчивается раздел ---------------------------------------------------------------------------- 0x06 2 Номер цилиндра и номер сектора, которыми заканчивается раздел ---------------------------------------------------------------------------- 0x08 4 Абсолютный (логический) номер начального сектора раздела ---------------------------------------------------------------------------- 0x0C 4 Размер раздела (число секторов) Первым байтом в элементе раздела идет флаг активности раздела (0 - неактивен, 0x80 - активен). Он служит для определения, является ли раздел системным загрузочным и есть ли необходимость производить загрузку операционной системы с него при старте компьютера. Активным может быть только один раздел. За флагом активности раздела следуют координаты начала раздела - три байта, означающие номер головки, номер сектора и номер цилиндра. Номера цилиндра и сектора задаются в формате прерывания Int 0x13, т.е. биты 0-5 содержат номер сектора, биты 6-7 - старшие два бита 10-разрядного номера цилиндра, биты 8-15 - младшие восемь битов номера цилиндра. Затем следует кодовый идентификатор System ID, указывающий на принадлежность данного раздела к той или иной операционной системе. Идентификатор занимает один байт. За системным идентификатором расположены координаты конца раздела - три байта, содержащие номера головки, сектора и цилиндра, соответственно. Следующие четыре байта - это число секторов перед разделом, и последние четыре байта - размер раздела в секторах. Таким образом, элемент таблицы раздела можно описать при помощи следующей структуры: struct pt_struct { u8 bootable; // флаг активности раздела u8 start_part[3]; // координаты начала раздела u8 type_part; // системный идентификатор u8 end_part[3]; // координаты конца раздела u32 sect_before; // число секторов перед разделом u32 sect_total; // число секторов в разделе }; Элемент первичного раздела указывает сразу на загрузочный сектор логического диска (в первичном разделе всегда имеется только один логический диск), а элемент расширенного раздела - на список логических дисков, составленный из структур, которые именуются вторичными MBR (Secondary MBR, SMBR). Свой блок SMBR имеется у каждого диска расширенного раздела. SMBR имеет структуру, аналогичную MBR, но загрузочная запись у него отсутствует (заполнена нулями), а из четырех полей описателей разделов используются только два. Первый элемент раздела при этом указывает на логический диск, второй элемент указывает на следующую структуру SMBR в списке. Последний SMBR списка содержит во втором элементе нулевой код раздела. Рассмотрим программу, отображающую информацию обо всех разделах (основных и логических), созданных на жестком диске. Программа функционирует под управлением ОС Linux. Заголовочные файлы: #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <linux/types.h> Сигнатура MBR: #define SIGNATURE 0xAA55 Файл устройства, с которого будет считываться информация о разделах: #define DEVICE "/dev/hda" Размер элемента таблицы разделов (0x10): #define PT_SIZE 0x10 Следующий массив структур устанавоивает соответствие между кодом типа раздела и его символьным отображением: struct systypes { __u8 part_type; __u8 *part_name; }; /* Этот массив взят из исходных текстов программы fdisk */ struct systypes i386_sys_types[] = { {0x00, "Empty"}, {0x01, "FAT12"}, {0x04, "FAT16 <32M"}, {0x05, "Extended"}, {0x06, "FAT16"}, {0x0b, "FAT32"}, {0x0c, "FAT32 (LBA)"}, {0x0e, "FAT16 (LBA)"}, {0x0f, "Win Ext'd (LBA)"}, {0x82, "Linux swap"}, {0x83, "Linux"}, {0x85, "Linux extended"}, {0x07, "HPFS/NTFS"} }; Определим число элементов в массиве i386_sys_types при помощи макроса: #define PART_NUM (sizeof(i386_sys_types) / sizeof(i386_sys_types[0])) int hard; // дескриптор файла устройства __u8 mbr[512]; // сюда считаем MBR Установим ограничение на количество логических дисков: #define MAX_PART 20 Следующий массив структура будет содержать информацию о логических дисках на устройстве (жестком диске): struct pt_struct { __u8 bootable; __u8 start_part[3]; __u8 type_part; __u8 end_part[3]; __u32 sect_before; __u32 sect_total; } pt_t[MAX_PART]; Рассмотрим главную функцию. int main() { int i = 0; __u64 seek; /* Открываем файл устройства, считываем таблицу разделов и проверяем сигнатуру */ hard = open(DEVICE, O_RDONLY); if(hard < 0) { perror("open"); exit(-1); } read_main_ptable(); if(check_sign() < 0) { printf("Not valid signature!\n"); exit(-1); } /* Ищем идентификатор расширенного раздела. Если таковой имеется - вычисляем * смещение к расширенному разделу и считываем информацию о логических дисках */ for(; i < 4; i++) { if((pt_t[i].type_part == 0xF) || \ (pt_t[i].type_part == 0x5) || \ (pt_t[i].type_part == 0x0C)) { seek = (__u64)pt_t[i].sect_before * 512; read_ext_ptable(seek); break; } } /* Отображаем информацию о логических дисках */ pt_info(); return 0; } Функция проверки сигнатуры 0xAA55 выглядит следующим образом: int check_sign() { __u16 sign = 0; memcpy((void *)&sign, (void *)(mbr + 0x1FE), 2); printf("Сигнатура - 0x%X\n", sign); if(sign != SIGNATURE) return -1; return 0; } Функция чтения таблицы разделов: void read_main_ptable() { if(read(hard, mbr, 512) < 0) { perror("read"); close(hard); exit(-1); } memset((void *)pt_t, 0, (PT_SIZE * 4)); memcpy((void *)pt_t, mbr + 0x1BE, (PT_SIZE * 4)); return; } Функция чтения расширенной таблицы разделов: void read_ext_ptable(__u64 seek) { int num = 4; // начиная с этой позиции, массив структур pt_t будет // заполняться информацией о логических дисках __u8 smbr[512]; /* Функция принимает один параметр seek - смещение (в байтах) к расширеному разделу * от начала диска. Для получения информации о логических дисках организуем цикл */ for(;;num++) { /* Считываем SMBR, находящуюся по смещению seek от начала диска */ memset((void *)smbr, 0, 512); pread64(hard, smbr, 512, seek); /* Заполняем два элемента таблицы pt_t, начиная с num. Первый элемент будет * указывать на логический диск, а второй - на следующую структуру SMBR */ memset((void *)&pt_t[num], 0, PT_SIZE * 2); memcpy((void *)&pt_t[num], smbr + 0x1BE, PT_SIZE * 2); /* Вносим поправку в поле "Номер начального сектора" - * отсчет ведется от начала диска */ pt_t[num].sect_before += (seek / 512); /* Если код типа раздела равен нулю, то больше логических дисков нет */ if(!(pt_t[num + 1].type_part)) break; /* Вычисляем смещение к следующей SMBR */ seek = ((__u64)(pt_t[num].sect_before + pt_t[num].sect_total)) * 512; } return; } Функция pt_info() отображает информацию о найденых логических дисках на устройстве: void pt_info() { int i, n; /* Информация о разделах на устройстве ATA-0 */ printf("\nNum\tBootable\tStart\tTotal\t\tId\tType\n"); for(i = 0; i < MAX_PART; i++) { if(!pt_t[i].type_part) { if(i < 4) continue; else break; } printf("%d\t", i + 1); if(pt_t[i].bootable == 0x80) printf("*\t"); else printf("\t"); printf("%12u\t", pt_t[i].sect_before); printf("%8u\t", pt_t[i].sect_total); printf("0x%.2X\t", pt_t[i].type_part); for(n = 0; n < PART_NUM; n++) { if(pt_t[i].type_part == i386_sys_types[n].part_type) { printf("%s\n", i386_sys_types[n].part_name); break; } } if(n == PART_NUM) printf("unknown type\n"); } return; } Рассмотрим пример функционирования программы. Имеется жесткий диск, подключеный как Primary Master. На диске созданы три основных раздела (FAT32 и два EXT2 раздела) и расширенный раздел в составе одного логического диска с файловой системой FAT32. Результат работы программы: # ./part_view Сигнатура - 0xAA55 Num Bootable Start Total Id Type 1 * 63 4096512 0x0B FAT32 2 4096575 30732345 0x0F Win Ext'd (LBA) 3 34828920 12289725 0x83 Linux 4 47118645 31037580 0x83 Linux 5 4096638 30732282 0x0B FAT32 Для контроля получим информацию о логических дисках при помощи fdisk: # fdisk -l -u Disk /dev/hda: 40.0 GB, 40020664320 bytes 255 heads, 63 sectors/track, 4865 cylinders, total 78165360 sectors Units = sectors of 1 * 512 = 512 bytes Device Boot Start End Blocks Id System /dev/hda1 * 63 4096574 2048256 b Win95 FAT32 /dev/hda2 4096575 34828919 15366172+ f Win95 Ext'd (LBA) /dev/hda3 34828920 47118644 6144862+ 83 Linux /dev/hda4 47118645 78156224 15518790 83 Linux /dev/hda5 4096638 34828919 15366141 b Win95 FAT32

<< Предыдущая ИНДЕКС Правка src / Печать Следующая >>

Обсуждение [ RSS ]
  • 1.1, BigShadow (?), 12:22, 22/03/2006 [ответить]  
  • +/
    "Разделы диска могут быть двух типов - primary (первичный, основной) и extended (расширенный). ... Extended-раздел может быть разделен на большое количество подразделов -
    логических дисков." - может все-таки тогда так:
    Разделы диска бывают трех типов - primary (первичный, основной), extended (расширенный) и logical (логический).

    Наличие на диске хотя бы одного primary-раздела является обязательным.
    ?! СОВСЕМ НЕ ФАКТ

     
  • 1.2, BigShadow (?), 12:27, 22/03/2006 [ответить]  
  • +/
    "Активным может быть только один раздел."
    На самом деле не "может быть", а ДОЛЖЕН БЫТЬ ;)
     
  • 1.3, GGG (?), 13:54, 03/04/2006 [ответить]  
  • +/
    Спасибо автору, очень толково написано.
    Под FreeBSD, кстати, штатный fdisk игнорирует logical-слайсы...
    А вообще создатели такой схемы разбиения недальновидно поступили, создав всего 4 раздела. Теперь каждая прога, как хочет, так ими и распоряжается, забивая на "стандарт". Я видел, как PartitionMagic  создал da0s2 вместо da0s1
     
  • 1.4, Arpan (?), 11:01, 19/12/2006 [ответить]  
  • +/
    Прочитал статью, смотрю на свой диск. Раздел Logical  Bootable, раздел Primary Active. Как так получилось? Это показывает PartitionMagic 8.0.
     
  • 1.5, Ruff (?), 19:16, 07/12/2010 [ответить]  
  • +/
    >Наличие на диске хотя бы одного primary-раздела является обязательным.

    Ошибаетесь. У меня нет первичного раздела.

     
  • 1.6, Mike (??), 14:11, 02/04/2012 [ответить]  
  • +/
    У меня 2 физических HDD. На втором специально при разметке создал только один расширенный раздел, а в нём уже один логический диск.

    >>>Разделы диска бывают трех типов - primary (первичный, основной), extended (расширенный) и logical (логический).

    Нет. Типов разделов всего 2: основной и расширенный. А вот на расширенном разделе можно уже создавать один или несколько логических дисков.

     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру