Все структуры, описывающие части файловой системы, взяты из Linux 2.4.0, i386, linux/include/linux/ext2_fs.h (C) 1991, 1992 Linus Torvalds
ext2 пришла на замену более древней ФС ext . Благодаря своей сокорости она может служить эталоном в тестах производительности файловых систем, но скорость была достигнута благодаря отказу от технологии журналирования, что делает ее неплохой системой для SSD накопителей, т.к. отсуствие журналирования является в данном случае преимуществом.
Физическая организация файловой системы[]
Файловую систему можно представить в виде следующей структурной схемы:
- Суперблок (Superblock)
- Описание группы блоков (Block Group Descriptors)
- Битовая карта блоков (Blocks Bitmap)
- Битовая карта индексных дескрипторов (Inode Bitmap)
- Таблица индексных дескрипторов (Inode Table)
- Данные
Все пространство раздела диска разбивается на так называемые блоки, имеющие порядковые номера. Блоки имеют фиксированный размер и кратны размеру сектора (1024,2048,4096...). Для уменьшения количества перемещений головки жесткого диска блоки объединяют в группы блоков.
Одним из базовых понятий ext2 является понятие индексного дескриптора (inode, инод, айнод). Это специальная структура, содержащая в себе информацию об физическом расположении файла/директории/ссылки и т.п. и его атрибутах.
Суперблок[]
Суперблок - одно из базовых понятий в ФС ext2. Суперблок содержит в себе общую информацию о файловой системе и находится в 1 килобайте от начала раздела. От цельности суперблока сильно зависит работоспособность ФС, и многие ОС создают его резервные копии на случай повреждения. Блок в виде структуры на языке программирования С представлен ниже:
struct ext2_super_block { __u32 s_inodes_count; /* Количество индексных дескрипторов в ФС */ __u32 s_blocks_count; /* Количество блоков в ФС */ __u32 s_r_blocks_count; /* Количество зарезервированых блоков */ __u32 s_free_blocks_count; /* Количество свободных блоков */ __u32 s_free_inodes_count; /* Количество свободных индексных дескрипторов */ __u32 s_first_data_block; /* Номер данного блока */ __u32 s_log_block_size; /* log2(размер блока)-10 */ __s32 s_log_frag_size; /* log2(размер фрагмента)-10 */ __u32 s_blocks_per_group; /* # Кол-во блоков в группе */ __u32 s_frags_per_group; /* # Кол-во фрагментов в группе */ __u32 s_inodes_per_group; /* # Кол-во индексных дескрипторов в группе */ __u32 s_mtime; /* Время последнего монтирования в POSIX времени */ __u32 s_wtime; /* Время последней записи в POSIX времени */ __u16 s_mnt_count; __s16 s_max_mnt_count; __u16 s_errors; /* Код ошибки(см.ниже) */ __u16 s_pad; __u32 s_lastcheck; /* POSIX время последней проверки */ __u32 s_checkinterval; /* POSIX время между принудительными проверками */ __u32 s_creator_os; /* ID ОС (см. ниже) */ __u32 s_rev_level; /* Версия */ __u16 s_def_resuid; /* UserID, могущий использовать зар. блоки */ __u16 s_def_resgid; /* GroupID, могущий использовать зар. блоки */ __u32 s_reserved[235]; /* Зарезервировано */ };
0 | Linux |
1 | GNU HURD |
2 | MASIX |
3 | FreeBSD |
4 | Other/Unknown |
BGD[]
BGD таблица содержит индексные дескрипторы для каждой группы блоков файловой системы и распологается сразу после суперблока. Таким образом, если указано, что размер блока составляет 1 кб, то блок с таблицей начинается в втором блоке. Блоки нумеруются с нуля, и номера блоков не соответствуют их физическому нахождению. Формат дескриптора группы блоков в виде структуры представлен ниже:
struct ext2_group_desc { __u32 bg_block_bitmap; /* Номер блока в битовой карте*/ __u32 bg_inode_bitmap; /* Дескриптор блока в битовой карте */ __u32 bg_inode_table; /* Номер блока в таблице дескрипторов */ __u16 bg_free_blocks_count; /* Свободно блоков */ __u16 bg_free_inodes_count; /* Свободно индексных дескрипторов */ __u16 bg_used_dirs_count; /* Количество директорий */ __u16 bg_pad; __u32 bg_reserved[3]; };
Индексные дескрипторы[]
В первой версии файловой системы индексные дескрипторы имели фиксированный размер в 128Кб, начиная с версии 1.0 размер инода указывается в соответствующем поле суперблока. Как и блоки, каждый дескриптор имеет свой номер, отличие лишь в том, что нумерация инодов начинается с единицы. До версии Ext2 1.0 дескрипторы с 1 по 10 были зарезервированы, но начиная с версии 1.0 первый незарезервированный инод отражается с помощью поля в суперблоке. Второй инод имеет самое большое значение, так как он используется для корневого каталога.
Поиск местонахождения дескриптора[]
Для определения того, какую группу блоков "представляет" данный индексный дескриптор, можно воспользоваться формулой:
Группа блоков = (инод-1) / s_inodes_per_group
где s_inodes_per_group соответствующее поле в суперблоке (см. Суперблок).
Как только мы узнали, какую группу представляет инод, мы можем узнать адрес нашего инода в таблице дескрипторов:
Адрес = (инод-1) % s_inodes_per_group
где % - деление по модулю.
Следующим шагом будет определение адреса блока, содержащего данный индексный дескриптор:
Блок = (Адрес * inode_size) / block_size
Чтение информации из дескриптора[]
см. Система адресации данных Структура дескриптора
struct ext2_inode { __u16 i_mode; /* Тип файла и права доступа (см.ниже) */ __u16 i_uid; /* UserID */ __u32 i_size; /* Размер в байтах */ __u32 i_atime; /* POSIX время последнего обращения к файлу */ __u32 i_ctime; /* POSIX время создания */ __u32 i_mtime; /* POSIX время последней модификации */ __u32 i_dtime; /* POSIX время удаления */ __u16 i_gid; /* GroupID */ __u16 i_links_count; /* Кол-во ссылок на дескриптор */ __u32 i_blocks; /* Кол-во секторов (не блоки!) */ __u32 i_flags; /* Флаг (см.ниже) */ union { struct { __u32 l_i_reserved1; /* Зарезервировано */ } linux1; struct { __u32 h_i_translator; /* ??? */ } hurd1; struct { __u32 m_i_reserved1; /* Зарезервировано */ } masix1; } osd1; __u32 i_block[EXT2_N_BLOCKS];/* Указатели на блок */ __u32 i_generation; /* Версия файла (для NFS) */ __u32 i_file_acl; /* Доп. аттрибуты файла */ __u32 i_dir_acl; /* Доп. аттрибуты директории */ __u32 i_faddr; /* Адрес фрагмента */ union { struct { __u8 l_i_frag; /* Номер фрагмента */ __u8 l_i_fsize; /* Размер фрагмента */ __u16 i_pad1; /* Зарезервировано */ __u16 l_i_uid_high; /* 16 старших битов UserID */ __u16 l_i_gid_high; /* 16 старших битов GroupID */ __u32 l_i_reserved2; /* Зарезервировано */ } linux2; /* LINUX */ struct { __u8 h_i_frag; /* Номер фрагмента */ __u8 h_i_fsize; /* Размер фрагмента */ __u16 h_i_mode_high; /* 16 старших битов T&P */ __u16 h_i_uid_high; /* 16 старших битов UserID */ __u16 h_i_gid_high; /* 16 старших битов GroupID */ __u32 h_i_author; /* UserID или автор */ } hurd2; /* GNU HURD */ struct { __u8 m_i_frag; /* Номер фрагмента */ __u8 m_i_fsize; /* Размер фрагмента */ __u16 m_pad1; /* Зарезервировано */ __u32 m_i_reserved2[2]; /* Зарезервировано */ } masix2; /* MASIX */ } osd2; /* Специфичные значения */ };
Тип файла и права доступа[]
В верхних четырех битах (15 по 12) поля i_mode находятся описания типа файла, а в остальных - права доступа.
0x1 | FIFO |
0x2 | Символьное устройство |
0x4 | Директория |
0x6 | Блочное устройство |
0x8 | Регулярный файл |
0xA | Ссылка |
0xC | UNIX-cокет |
Для представления прав доступа в UNIX используется 10 битное поле, маску которого можно представить как DRWERWERWE (в данном случае нужно просто "отсечь" последние два бита) , где первый бит указывает, является ли файл специальным. Первая RWE тройка указывает права пользователя на чтение, запись, и исполнение файла, вторая - на права группы пользователя, третья - права для всех остальных. К примеру, если получена последовательность битов 0111101101 , то данный файл не является директорией, его могут исполнить и читать все "пользователи" данного компьютера, но редактировать позволено только пользователю-создателю.
Система адресации данных[]
Для хранения адреса файла выделено 15 полей по 4 байта. Если файл умещается в пределах 12 блоков, то в первых 12 полях адреса перечислены номера соответствующих кластеров, иначе следующее поле используется для косвенной адресации. Возможна ситуация, когда размер файла превышает 1024+12 блоков. Тогда 14 поле используется для двойной косвенной адресации, но если вдруг файл включает в себя более 1049612 блоков, в дело вступает тройная косвенная адресация и 15 блок. Такая организация позволяет при максимальном размере блока в 4Кб оперировать файлами, размер которых превышает 2Тб. Наглядно данная схема показана на рисунке ниже: