Второе рождение утерянных данных под LINUX'ом

       

Структура файловой системы


В противовес WindowsNT, поддерживающей только NTFS и FAT, операционные системы семейства LINUX предлагают довольно широкий ассортимент файловых систем на любой вкус: ext2fs, ext3fs, reiserfs, xfs, jfs и т. д. При внешней схожести "потребительских" возможностях, их "физическое" устройство сильно неодинаково и каждая из них требует своей техники восстановления. В рамках одной-единственной статьи поднять эту глыбу нереально, поэтому мы решили остановится на ext2fs/ext3fs как на самой популярной файловой системе, устанавливаемой по умолчанию большинством дистрибьютивов.

Рисунок 2 восстановление удаленных файлов с ext2fs раздела с помощью Windows-утилиты R-Studio — есть файлы, но нету имен

Файловые системы ext2fs и ext3fs очень похожи друг на друга. Фактически, ext3fs это ext2fs с поддержкой журналирования. Отличия базовых структур минимальны, но вот процесс удаления файлов в них протекает по разному. В ext2fs при удалении файла теряется его имя (хотя и не затирается до поры до времени), поэтому автоматическое восстановление имен в ней невозможно, зато само содержимое файла остается нетронутым. Ext3fs поступает с точностью до наоборот — сохраняет имя файла, но частично уничтожает схему его размещения на диске, в результате чего техника восстановления колоссально усложняется. К тому же ext3fs намного менее производительна, так что для домашних компьютеров лучше всего использовать ext2fs. Как она устроена?

Рисунок 3 восстановление удаленных файлов с ext3fs раздела — есть имена, но нету файлов (поле размера равно нулю, что означает отсутствие данных)

В начале раздела расположен boot-сектор, за ним, по смещению 1024 байта находится супер-блок (super-block), отвечающий за хранение ключевой информации о структуре файловой системы (в ext2fs/ext3fs он играет точно такую же роль, что и boot-сектор в FAT и NTFS). В нем много всяких полей, но нас будет интересовать лишь одно: s_log_block_size. Это 32-разрядное поле, расположенное по смещению 18h байт от начала супер-блока. Как и следует из его названия, оно определяет размер одного блока


(block) или, в терминологии MS-DOS/Windows, кластера. Размер задается в виде показателя степени на которую сдвигается размер одного сектора, равный 200h (512) байт. В переводе на программистский язык это звучит так:

block_size = 200h << s_log_block_size (байт). Например, если s_log_block_size

равен нулю, размер одного блока будет 400h байт, то есть два сектора.

  смещение     размер описание

------- ------- -----------



       0           1 boot record         ; загрузочный сектор

         -- block group 0 --                    ; группа блоков 0

(1024 bytes)       1 superblock          ; суперблок

       2           1 group descriptors   ; дескриптор группы

       3           1 block bitmap        ; карта свободных блоков

       4           1 inode bitmap        ; карта свободных inode

       5         214 inode table         ; массив inode (сведения о файлах)

     219        7974 data blocks         ; блоки данных (файлы, директории)

         -- block group 1 --                    ; группа блоков 1

    8193           1 superblock backup   ; копия

суперблока

    8194           1 group descriptors backup ; копия

дескрпиора группы

    8195           1 block bitmap        ; карта свободных блоков

    8196           1 inode bitmap        ; карта свободных inode

    8197         214 inode table         ; массив inode (сведения о файлах)

    8408        7974 data blocks         ; блоки данных (файлы, директории)

         -- block group 2 --                    ; группа блоков 2

   16385           1 block bitmap        ; карта свободных блоков

   16386           1 inode bitmap        ; карта свободных inode

   16387         214 inode table         ; массив inode (сведения о файлах)

   16601        3879 data blocks         ; блоки данных (файлы, директории)

Листинг 1 структура дискового тома, размеченного под ext2fs

За супер-блоком идут так называемые дескрипторы групп (group descriptors), и карты свободного пространства, в просторечии — битмапы (block bitmap/inode bitmap), которые нам малоинтересны, а вот примыкающую к ним indoe-таблицу, мы рассмотрим поподробнее, поскольку без знания ее структуры ручное восстановление данных просто немыслимо.



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

смещение   размер описание

------- ------- -----------

    0       2 i_mode       ; формат представления описание

    2       2 i_uid        ; uid пользователя

    4       4 i_size       ; размер файла в байтах

    8       4 i_atime             ; время последнего доступа к файлу

   12       4 i_ctime             ; время создания файла

   16       4 i_mtime             ; время модификации файла

   20       4 i_dtime             ; время удаления файла

   24       2 i_gid        ; gid группы

   26       2 i_links_count ; количество ссылок на файл (0 – файл удален)

   28       4 i_blocks            ; количество блоков, принадлежащих файлу

   32       4 i_flags             ; разные флаги

   36       4 i_osd1       ; OS dependant value

   40  12 x 4 i_block             ; 12 DIRECT BLOCKS (ссылки на первые 12 блоков файла)

   88       4 i_iblock            ; 1x INDIRECT BLOCK

   92       4 i_2iblock    ; 2x INDIRECT BLOCK

   96       4 i_3iblock    ; 3x INDIRECT BLOCK

  100       4 i_generation ; поколение файла (используется NFS)

  104       4 i_file_acl   ; внешние

атрибуты

  108       4 i_dir_acl    ; higer size

  112       4 i_faddr             ; положение последнего фрагмента

  116      12 i_osd2       ; OS dependant structure

Листинг 2 формат представления inode

Схема размещения файла на диске организована намного проще, чем в NTFS и FAT. Каждый файл занимает один или несколько блоков. Даже если блок занят только частично, он выделяется файлу целиком (в остальных файловых системах, таких например, как UFS, предусмотрена возможность выделения файлу только части блока, а в NTFS и ReiserFS мелкие файлы могут храниться непосредственно в самой inode, что существенно уменьшает фрагментацию и увеличивает производительность), но вернемся к ext2fs/ext3fs.



Указатели на 12  первых блоков, занимаемых файлом, хранятся прямо в inod'е, а точнее — в массиве DIRECT BLOCKS, так же называемом массивом непосредственных блоков. Каждый элемент массива представляет собой 32-битный номер блока. Поскольку, типичный размер блока составляет ~4 Кбайт (конкретное значение зависит от емкости диска и опций форматирования), то массив непосредственных блоков "переваривает" файлы до 4 12 == 48 Кбайт. Если длина файла превышает эту величину (а у подавляющего большинства файлов она превышает), приходится прибегать к блокам косвенной адресации. (или по-английски INDIRECT BLOCK). Файловые системы ext2fs/ext3fs поддерживают три уровня вложенности. Первый блок косвенной адресации (1x INDIRECT BLOCK или просто INDIRECT BLOCK) хранит уже не указатели на блоки занятые файлов, а указатели на дополнительные непосредственные блоки и может адресовать до BLOCK_SIZE/sizeof(DWORD) * BLOCK_SIZE = 4096/4 *4 Мбайт данных. Что ж! Полвека назад это была очень большая величина, но сейчас ею никого не удивишь и большинству из нас требуется обрабатывать намного более "толстые" файлы. На этот случай предусмотрен блок двойной косвенной адресации (2x INDIRECT BLOCK) или DOUBLE INDIRECT BLOCK, хранящий указатели на косвенные блоки, которые в свою очередь хранят ссылки на непосредственные блоки, что позволяет адресовать (BLOCK_SIZE/sizeof(DWORD))**2* BLOCK_SIZE =4096/4 ** 4096 == 4 Гбайт данных. Это уже внушительная величина, при которой размер файла занимает всю разрядную сетку 32-битной переменной. Большинство приложений ограничивают верхний размер обрабатываемых файлов 2 или 4 Гбайтами, тем не менее, файловая система способна хранить файлы намного большего размера. Это осуществляется с помощью трижды косвенного блока (3x INDIRECT BLOCK или TRIPLE INDIRECT BLOCK), указывающего на дважды косвенные блоки, каждый из которых указывает на косвенные блоки, ссылающиеся на блоки непосредственной адресации. Так что возможности ext2fs/ext3fs намного превышают емкости жестких дисков настоящего и будущего.



По сравнению с FAT, такая схема хранения информации об размещении, является намного более устойчивой к разрушениям. Она как бы "размазывается" по всему диску и уничтожить все блоки адресации можно разве что динамитом. К тому же, номера блоков хранятся в прямом виде "как есть", а это значит, что для каждого блока файла мы может быстро найти соответствующий ему косвенный блок, даже если inod'а полностью разрушена.



Рисунок 4 описание порядка размещения файла на диске, иерархия непосредственных и косвенных блоков

Имена файлов хранятся в директориях и в inode их нет. Директории представляют собой обычные файлы… ну, хорошо, не совсем обычные, а специальные служебные файлы, содержащие массив записей типа:

смещение  размер описание

------- ------- -----------

      0       4 inode             ; ссылка на inod'у

      4       2 rec_len    ; длина данной записи

      6       1 name_len   ; длина имени файла

      7       1 file_type  ; тип

файла

      8     ... name       ; имя файла

Листинг 3 формат представления массива директорий

Поле inode содержит порядковый номер inode, которому соответствует данное имя файла; поле rec_len задает длину текущей записи, а name_len – длину имени файла. Само имя хранится в ASCII виде сразу после длины.


Содержание раздела