The OpenNET Project / Index page

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

Логическая структура жесткого диска (linux disk partition gcc)


<< Предыдущая ИНДЕКС Правка src / Печать Следующая >>
Ключевые слова: linux, disk, partition, gcc,  (найти похожие документы)
From: Bob <ubob@mail.ru.> Date: Mon, 4 Dec 2006 13:01:37 +0000 (UTC) Subject: Логическая структура жесткого диска Когда-то давно мною была опубликована статья под названием "Логическая структура жесткого диска", http://www.opennet.dev/base/dev/hdd_struct.txt.html Но код программы в этой статье содержит ошибки. Первая, и самая существенная - если количество основных разделов не равно четырем, то программа выдаст неправильную информацию о структуре диска. Вторая ошибка не критичная, но тем не менее также требует устранения. Дело в том, что для хранения информации о логических дисках расширенного раздела используется массив на фиксированное число элементов. В этой статье будут устранены обе ошибки. Информации о логических дисках будет храниться в виде однонаправленного списка. Для организации списка воспользуемся макросами, которые определены в <sys/queue.h>, в частности, семейством TAILQ. Порядок использования этих макроопределений подробно изложен в man queue. Все теоретические вопросы о логической структуре жесткого диска и форматы ключевых структур данных рассматривались в предыдущей статье (см. ссылку выше), поэтому приступим непосредственно к переделке кода программы. Элемент списка разделов будет выглядеть следующим образом: typedef struct pt_entry { u8 bootable; u8 start_part[3]; u8 type; u8 end_part[3]; u32 sect_before; u32 sect_total; TAILQ_ENTRY(pt_entry) entries; } pt_entry_t; Голова списка: TAILQ_HEAD(,pt_entry) head; Предварительно этот список надо проинициализировать вызовом: TAILQ_INIT(&head); Функция чтения основной таблицы разделов из MBR. Параметры функции: - int dev - дескриптор открытого устройства - u64 *seek - смещение к расширенному разделу, если таковой есть. Как видно, параметр передается по ссылке. int read_main_ptable(int dev, u64 *seek) { int i = 0; u8 mbr[512]; pt_entry_t *part = NULL; /* Считываем MBR */ if(read(dev, mbr, 512) < 0) return -1; /* Проверяем сигнатуру */ if(*(u16 *)(mbr + 0x1FE) != 0xAA55) return -1; /* Цикл чтения основных разделов */ for(;i < 4; i++) { part = (pt_entry_t *)calloc(1, sizeof(pt_entry_t)); if(!part) return -1; /* Копируем с диска элемент раздела в соотв. структуру */ memcpy((void *)part, mbr + 0x1BE + PT_SIZE * i, PT_SIZE); /* Если это расширенный раздел, вычисляем смещение к нему */ if(part->type == 0x0F || part->type == 0x05 || part->type == 0x0C) *seek = (u64)(part->sect_before) * 512; /* Ставим элемет в конец списка */ TAILQ_INSERT_TAIL(&head, part, entries); } return 0; } Функция чтения элементов расширенной таблицы разделов. В параметрах передаем смещение к расширенному разделу от начала диска (в байтах): int read_ext_ptable(int dev, u64 seek) { u8 smbr[512]; pt_entry_t *part = NULL, tmp; for(;;) { part = (pt_entry_t *)calloc(1, sizeof(pt_entry_t)); if(!part) return -1; /* Считываем SMBR */ memset(smbr, 0, sizeof(smbr)); lseek(dev, seek, SEEK_SET); if(read(dev, smbr, sizeof(smbr)) < 0) return -1; /* Первая запись SMBR - информация о логическом диске */ memcpy((void *)part, smbr + 0x1BE, PT_SIZE); /* Вносим правку в поле "Номер начального сектора" - отсчет ведется от начала диска */ part->sect_before += (u32)(seek/512); /* Помещаем элемент в конец списка */ TAILQ_INSERT_TAIL(&head, part, entries); /* Вторая запись SMBR - указатель на следующую SMBR */ memset(&tmp, 0, PT_SIZE); memcpy((void *)&tmp, smbr + 0x1BE + PT_SIZE, PT_SIZE); /* Если код типа раздела равен 0, то больше логических дисков расширенный раздел не содержит */ if(!tmp.type) return 0; /* Вычисляем смещение к следующему SMBR */ seek = (u64)(part->sect_before + part->sect_total) * 512; } } Функция info занимается выводом информации о разделах на экран: void info() { int i = 1; pt_entry_t *part; for(part = (&head)->tqh_first;(part);part = part->entries.tqe_next) { fprintf(stderr,"%d\t", i++); fprintf(stderr,"%8u\t", part->sect_before); fprintf(stderr,"%8u\t", part->sect_total + part->sect_before - 1); fprintf(stderr,"%x\t", part->type); } } Полный листинг программы для чтения информации о разделах на диске находится в файле part.c. Для его сборки достаточно ввести команду: gcc -Wall -g -o part part.c При запуске в командной строке необходимо указать файл устройства, информацию с которого вы хотите прочитать, например: ./part /dev/hda
part.c #include <stdio.h> #include <stdlib.h> #include <string.h> #ifndef __USE_FILE_OFFSET64 #define __USE_FILE_OFFSET64 #endif #ifndef __USE_LARGEFILE64 #define __USE_LARGEFIEL64 #endif #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/queue.h> typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; /* Размер элемента таблицы разделов */ #define PT_SIZE 0x10 /* Флаг загрузочного раздела */ #define BOOTABLE 0x80 #pragma pack(1) struct systypes { u8 part_type; u8 * part_name; }; typedef struct pt_entry { u8 bootable; u8 start_part[3]; u8 type; u8 end_part[3]; u32 sect_before; u32 sect_total; TAILQ_ENTRY(pt_entry) entries; } pt_entry_t; /* from fdisk.c */ struct systypes i386_sys_types[] = { {0x00, "Пустой раздел"}, {0x01, "FAT12"}, {0x04, "FAT16 <32M"}, {0x05, "Расщиренный раздел DOS"}, /* DOS 3.3+ extended partition */ {0x06, "FAT16"}, /* DOS 16-bit >=32M */ {0x0b, "FAT32"}, {0x0c, "FAT32 (LBA)"}, /* LBA really is `Extended Int 13h' */ {0x0e, "FAT16 (LBA)"}, {0x0f, "Расширенный раздел Windows"}, {0x82, "раздел подкачки Linux (swap)"}, /* also Solaris */ {0x83, "Linux"}, {0x85, "Расширенный раздел Linux"}, {0x07, "HPFS/NTFS"} }; #define PART_NUM (sizeof(i386_sys_types)/sizeof(i386_sys_types[0])) int read_main_ptable(int, u64 *); int read_ext_ptable(int, u64); int get_pt_info(int); void info(); TAILQ_HEAD(,pt_entry) head; /* Считываем основную таблицу разделов из MBR */ int read_main_ptable(int dev, u64 *seek) { int i = 0; u8 mbr[512]; pt_entry_t *part = NULL; if(read(dev, mbr, 512) < 0) return -1; if(*(u16 *)(mbr + 0x1FE) != 0xAA55) return -1; for(;i < 4; i++) { part = (pt_entry_t *)calloc(1, sizeof(pt_entry_t)); if(!part) return -1; memcpy((void *)part, mbr + 0x1BE + PT_SIZE * i, PT_SIZE); /* Если присутствует расширенный раздел, запоминаем его номер */ if(part->type == 0x0F || part->type == 0x05 || part->type == 0x0C) *seek = (u64)(part->sect_before) * 512; TAILQ_INSERT_TAIL(&head, part, entries); } return 0; } int read_ext_ptable(int dev, u64 seek) { u8 smbr[512]; pt_entry_t *part = NULL, tmp; /* seek - смещение к расширенному разделу от начала диска (в байтах) */ for(;;) { part = (pt_entry_t *)calloc(1, sizeof(pt_entry_t)); if(!part) return -1; memset(smbr, 0, sizeof(smbr)); lseek(dev, seek, SEEK_SET); if(read(dev, smbr, sizeof(smbr)) < 0) return -1; memcpy((void *)part, smbr + 0x1BE, PT_SIZE); part->sect_before += (u32)(seek/512); TAILQ_INSERT_TAIL(&head, part, entries); memset(&tmp, 0, PT_SIZE); memcpy((void *)&tmp, smbr + 0x1BE + PT_SIZE, PT_SIZE); if(!tmp.type) return 0; /* Вычисляем смещение к следующему SMBR */ seek = (u64)(part->sect_before + part->sect_total) * 512; } } int get_pt_info(int dev) { u64 seek = 0; TAILQ_INIT(&head); if(read_main_ptable(dev, &seek) < 0) return -1; if(seek) read_ext_ptable(dev, seek); return 0; } /* Вывести информацию */ void info() { int i = 1, n = 0; pt_entry_t *part; for(part = (&head)->tqh_first;(part);part = part->entries.tqe_next) { fprintf(stderr,"%d\t", i++); fprintf(stderr,"%8u\t", part->sect_before); fprintf(stderr,"%8u\t", part->sect_total + part->sect_before - 1); fprintf(stderr,"%x\t", part->type); for(n = 0; n < PART_NUM; n++) { if(part->type == i386_sys_types[n].part_type) { fprintf(stderr, "%s\n", i386_sys_types[n].part_name); break; } } if(n == PART_NUM) fprintf(stderr,"неизвестный тип\n"); } } int main(int argc, char **argv) { int dev; if(!argv[1]) return 0; dev = open(argv[1], O_RDONLY); if(dev < 0) { perror("open"); return -1; } if(get_pt_info(dev) < 0) return -1; info(); return 0; }

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

Обсуждение [ RSS ]
  • 1, Skif (ok), 18:30, 28/12/2006 [ответить]  
  • +/
    Понравилось. В свое время упустил Вашу статью, теперь жалею.
     
  • 2, igor (??), 15:46, 30/03/2009 [ответить]  
  • +/
    В УСЛОВИИ ПРОВЕРКИ ЯВЛЯЕТСЯ ЛИ ДАННЫЙ РАЗДЕЛ РАСШИРЕННЫМ:
    0x0C <- разве это код расширенного раздела, а не обычного W95 FAT32 (LBA)
     
     
  • 3, alexmal (?), 21:22, 05/11/2010 [^] [^^] [^^^] [ответить]  
  • +/
    Имелось в виду 0x85 - Linux Extended
     

  • 4, scrat (?), 19:17, 01/09/2011 [ответить]  
  • +/
    В функции read_ext_ptable перед  lseek(dev, seek, SEEK_SET) не следует поставить lseek(dev,0,0). Да бы  при каждой новмой итерации расчитывать смещение от начала файла?
     
  • 5, scrat (?), 19:28, 01/09/2011 [ответить]  
  • +/
    И ещё вопрос: обязательно ли  два поля таблицы разделов EBR(Extended Boot Record)-smbr могут быть пустыми или возможны варианты? Может имеет смысл дополнительно  проверять эти поля пусты они или нет?


     

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




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

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