Книга: Восстановление данных. Практическое руководство

Восстановление удаленных файлов под ext2fs

Восстановление удаленных файлов под ext2fs

Файловая система ext2fs все еще остается базовой файловой системой для многих клонов Linux, поэтому рассмотрим ее первой. Концепции, которые она исповедует, во многом схожи с NTFS, так что культурного шока при переходе с NTFS на ext2fs вы не испытаете. Подробное описание структуры хранения данных ищите в документе "Design and Implementation of the Second Extended Filesystem" (см. список рекомендованной литературы и ресурсов Интернета в данном разделе), а также книге Эндрю Таненбаума "Operating Systems: Design and Implementation", электронную версию которой можно раздобыть в e-Mule. Исходные тексты дисковых утилит (драйвер файловой системы, lde, debugfs) также не помешают.

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

В начале диска расположен загрузочный сектор, который на незагрузочных разделах может быть пустым. За ним по смещению 1024 байта от начала первого сектора лежит суперблок (super-block), содержащий ключевую информацию о структуре файловой системы. В FAT и NTFS эта информация хранится непосредственно в загрузочном секторе. В первую очередь нас будет интересовать 32-разрядное поле s_log_block_size, расположенное по смещению 18h байт от начала суперблока. Здесь хранится размер одного блока (block) или, в терминологии MS-DOS/Windows, кластера, выраженный в виде указателя позиции, на которую нужно сдвинуть число 200h. В естественных единицах это будет звучать так: block_size == 200h << s_log_block_size (байт). То есть если s_log_block_size равен нулю, размер одного блока составляет 400h байт или два стандартных сектора. Структура дискового тома, отформатированного под ext2fs, показана в листинге 8.4.

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

смещение размер описание
-------- ------ --------
       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              ; Блоки данных
                                         ; (файлы, каталоги)

Вслед за суперблоком идут дескрипторы групп (group descriptors) и карты свободного пространства (block bitmap/inode bitmaps которые не имеют большого практического значения для наших целей. Что же касается таблицы inode, расположенной за ними, то она заслуживает более подробного рассмотрения. В ext2fs (как и многих других файловых системах из мира UNIX), так называемый индексный дескриптор (inode) играет ту же самую роль, что и файловая запись в NTFS. Здесь сосредоточена вся информация о файле: тип файла (обычный файл, каталог, символьная ссылка и т.д.), его логический и физический размер, схема размещения на диске, время создания, модификации, последнего доступа или удаления, права доступа, а также ссылки на файл. Формат представления inode описан в листинге 8.5.

Листинг 8.5. Формат представления inode

смещение размер описание
-------- ------ --------
       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_osdl        ; Значение, зависящее от ОС
      40 12 x 4 i_block       ; Ссылки на первые 12 блоков файла
      88      4 i_iblock      ; 1х 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     ; higher size
     112      4 i_faddr       ; Положение последнего фрагмента
     116     12 i_osd2        ; Структура, зависящая от ОС

Первые 12 блоков, занимаемых файлом, называются непосредственными блоками (для наглядности они выделены полужирным шрифтом). Они хранятся в массиве DIRECT BLOCKS непосредственно в теле inode. Каждый элемент массива представляет собой 32-битный номер блока. При среднем значении BLOCK_SIZE, равном 4 Кбайт, непосредственные блоки могут адресовать до 4?12 == 48 Кбайт данных. Если файл превышает этот размер, создаются один или несколько блоков косвенной адресации (INDIRECT BLOCK). Первый блок косвенной адресации (1x INDIRECT BLOCK или просто INDIRECT BLOCK) хранит ссылки на другие непосредственные блоки. Адрес этого блока хранится в поле i_indirect_block в inode. Как легко вычислить, он адресует порядка BLOCK_SIZE/sizeof(DWORD) * BLOCK_SIZE == 4096/4 *4 Мбайт данных. Если этого окажется недостаточно, создается косвенный блок двойной косвенной адресации (2х INDIRECT BLOCK или DOUBLE INDIRECT BLOCK), хранящий указатели на косвенные блоки, что позволяет адресовать (BLOCK_SIZE/sizeof(DWORD))**2* BLOCK_SIZE =4096/4 ** 4096 == 4 Гбайт данных. Если же и этого все равно недостаточно, создается блок тройной косвенной адресации (3х INDIRECT BLOCK или TRIPLE INDIRECT BLOCK), содержащий ссылки на блоки двойной косвенной адресации. Иерархия непосредственных блоков и блоков косвенной адресации показана на рис. 8.6 (блок тройной косвенной адресации не показан).


Рис. 8.6. Порядок размещения файла на диске — иерархия непосредственных и косвенных блоков (блок косвенной адресации третьего порядка не показан)

По сравнению с NTFS такая схема хранения информации о размещении устроена намного проще. Вместе с тем, она и гораздо "прожорливее". С другой стороны, ее несомненное достоинство по сравнению с NTFS состоит в том, что поскольку все ссылки хранятся в неупакованном виде, для каждого блока файла можно быстро найти соответствующий ему косвенный блок, даже если inode полностью разрушен!

Имя файла в inode не хранится. Ищите его внутри каталогов, представляющих собой массив записей, формат которого представлен в листинге 8.6.

Листинг 8.6. Формат представления массива каталогов

смещение размер описание
-------- ------ --------
       0      4 inode ; Ссылка на inode
       4      2 rec_len ; Длина данной записи
       6      1 name_len ; Длина имени файла
       7      1 file_type ; Тип файла
       8    ... name ; Имя файла

При удалении файла операционная система находит соответствующую запись в каталоге, обнуляет поле inode и увеличивает размер предшествующей записи (поле rec_len) на величину удаляемой записи. Таким образом, предшествующая запись "поглощает" удаленную. Хотя имя файла в течение некоторого времени остается нетронутым, ссылка на соответствующий ему индексный дескриптор (inode) оказывается уничтоженной. Это создает проблему, так как теперь придется разбираться, какому файлу принадлежит обнаруженное имя.

В самом индексном дескрипторе при удалении файла тоже происходят большие изменения. Количество ссылок (i_links_count) обнуляется и обновляется поле последнего удаления (i_dtime). Все блоки, принадлежащие файлу, в карте свободного пространства (block bitmap) помечаются как неиспользуемые, после чего данный inode также освобождается (обновляется inode bitmap).

Техника восстановления удаленных файлов

В ext2fs полное восстановление файлов невозможно, даже если эти файлы были только что удалены. В этом отношении данная файловая система проигрывает как FAT, так и NTFS. Как минимум, теряется имя файла. Точнее говоря, теряется связь имен файлов с их содержимым. При удалении небольшого количества хорошо известных файлов эта проблема остается решаемой. Однако ситуация серьезно осложняется, если вы удалили несколько служебных подкаталогов, в которых никогда ранее не заглядывали.

Достаточно часто индексные дескрипторы назначаются в том же порядке, в котором создаются записи в таблице каталогов. Благодаря наличию расширений имен файлов (.c, .gz, .mpg, и т.д.) количество возможных комбинаций соответствий обычно оказывается сравнительно небольшим. Тем не менее, восстановить удаленный корневой каталог в автоматическом режиме никому не удастся (а вот NTFS с этим справляется без труда).

В целом, стратегия восстановления выглядит приблизительно так: сканируем таблицу индексных дескрипторов (inode table) и отбираем все записи, чье поле i_links_count равно нулю. Сортируем их по дате удаления, чтобы файлы, удаленные последними, оказались в верхних позициях списка. Как вариант, если вы помните примерное время удаления файла, можно просто наложить фильтр. Если соответствующие индексные дескрипторы еще не затерты вновь создаваемыми файлами, извлекаем список прямых/косвенных блоков и записываем их в дамп, корректируя его размер с учетом "логического" размера файла, за который отвечает поле i_size.

Восстановление удаленных файлов с помощью редактора Lde

Откройте редактируемый раздел или его файловую копию с помощью команд lde my_dump или lde /dev/sdb1. Редактор автоматически определяет тип файловой системы (в данном случае — ext2fs) и предлагает нажать любую клавишу для продолжения. Lde автоматически переключается в режим отображения суперблока и предлагает нажать клавишу <I> для перехода в режим inode или клавишу <В> — для перехода в блочный режим (block-mode). Нажмите клавишу <I>, и вы окажетесь в первом индексном дескрипторе, описывающем корневой каталог. Нажатие клавиши <Page Down> перемещает нас к следующему inode, а нажатие клавиши <Page Up>, — соответственно, к предыдущему. Пролистываем список индексных дескрипторов вниз, обращая внимание на поле LINKS. У удаленных файлов это поле равно нулю, и тогда поле DELETION TIME содержит время последнего удаления. Обнаружив подходящий inode по запомненному времени удаления, перемещаем курсор к первому блоку в списке DIRECT BLOCKS (где он должен находиться по умолчанию) и нажимаем клавишу <F2>. В появившемся меню выбираем пункт Block mode, viewing block under cursor (или сразу нажимаем клавиатурную комбинацию <Shift>+<B>). Редактор перемещается на первый блок удаленного файла. Просматривая его содержимое в шестнадцатеричном режиме, пытаемся определить, тот ли это файл, который требуется восстановить. Если вы нашли именно тот файл, который намеревались восстановить, нажмите для его восстановления клавиатурную комбинацию <Shift>+<R>, затем — клавишу <R>, и введите имя файла, в который требуется восстановить дамп. Чтобы вернуться к просмотру следующего inode, нажмите клавишу <I>.

Можно восстанавливать файлы и по их содержимому. Например, предположим, что нам известно, что удаленный файл содержит строку hello, world. Нажимаем <f>, затем — клавишу <A> (Search all block). Этим мы заставляем редактор искать ссылки на все блоки, в том числе и удаленные. Как вариант, можно запустить редактор с ключом --all. Но, так или иначе, затем мы нажимаем клавишу <В>, и, когда редактор перейдет в блочный режим, нажимаем клавишу </> и вводим искомую строку в ASCII. Находим нужный блок. Прокручивая его вверх и вниз, убеждаемся, что он действительно принадлежит тому самому файлу. Если это так, нажимаем <Ctrl>+<R>, давая редактору указание просматривать все индексные дескрипторы, содержащие ссылку на этот блок. Номер текущего найденного inode отображается в нижней части экрана.

Внимание!

Номер текущего найденного inode отображается именно в нижней части экрана. В верхней части отображается номер последнего просмотренного inode в режиме inode.

Переходим в режим inode нажатием клавиши <I>, нажимаем клавишу <#> и вводим номер inode, который требуется просмотреть. Если дата удаления более или менее соответствует действительности, нажимаем <Shift>+<R>/<R> для сброса файла на диск. Если нет — возвращаемся в блочный режим и продолжаем поиск.

В сложных случаях, когда список прямых и/или косвенных блоков разрушен, восстанавливаемый файл приходится собирать буквально по кусочкам, основываясь на его содержимом и частично — на стратегии выделения свободного пространства файловой системой. В этом нам поможет клавиша <w>, дающая указание дописать текущий блок к файлу-дампу. В процессе восстановления мы просто перебираем все свободные блоки один за другим (редактор помечает их строкой NOT USED) и, обнаружив подходящий, дописываем в файл. Конечно, таким образом невозможно восстановить сильно фрагментированный двоичный файл, но вот восстановление листинга программы — вполне реалистичная задача.

На основании вышесказанного можно сделать вывод о том, что ручное восстановление файлов с помощью lde крайне непроизводительно и трудоемко. Однако при этом данный подход является наиболее "прозрачным" и надежным. Что касается восстановления оригинальных имен файлов, то эту операцию лучше всего осуществлять с помощью отладчика файловой системы debugfs.

Восстановление с помощью отладчика файловой системы debugfs

Загружаем в отладчик редактируемый раздел или его копию. Сделать это можно с помощью команд debugfs /dev/sdb1 или debugfs my_dump соответственно. Если мы планируем осуществлять запись на диск, необходимо указать ключ -w: debugfs -w my_dump или debugfs -w /dev/sdb1.

Чтобы просмотреть список удаленных файлов, даем команду lsdel (или lsdel t_sec, где t_sec — количество секунд, истекших с момента удаления файла). На экране появится список удаленных файлов (разумеется, без имен). Файлы, удаленные более t_sec секунд назад (если эта опция задана), в данный список не попадут.

Команда cat <N> выводит содержимое текстового файла на терминал. Здесь <N> — номер inode, заключенный в угловые скобки. При выводе двоичных файлов разобрать смысл отображаемой на экране информации практически невозможно. Такие файлы должны сбрасываться в дамп командой dump <N> new_filе_name, где new_file_name — новое имя файла (с путем), под которым он будет записан в файловую систему, из-под которой был запущен отладчик debugfs. Файловая система восстанавливаемого раздела при этом остается неприкосновенной. Иными словами, команда должна даваться без ключа --w.

При желании можно восстановить файл непосредственно на самой восстанавливаемой файловой системе (что особенно удобно при восстановлении больших файлов). В этом нам поможет команда undel <N> undel_file_name, где undel_file_name — имя, которое будет присвоено файлу после восстановления.

Внимание!

Выполняя такую операцию, помните, что команда undel крайне агрессивна и деструктивна по своей природе. Она затирает первую свободную запись в таблице каталогов, делая восстановление оригинальных имен невозможным.

Команда stat <N> отображает содержимое inode в удобочитаемом виде, а команда mi <N> позволяет редактировать их по своему усмотрению. Для ручного восстановления файла (откровенно говоря, этого не пожелаешь и врагу) мы должны установить счетчик ссылок (link count) на единицу, а время удаления (deletion time), наоборот, сбросить в ноль. Затем отдать команду seti <N>, помечающую данный inode как используемый, и для каждого из блоков файла выполнить команду setb X, где X — номер блока.

Совет

Перечень блоков, занимаемых файлом, можно просмотреть с помощью команды stat. В отличие от lde, она отображает не только непосредственные, но и косвенные блоки, что несравненно удобнее.

Остается только дать файлу имя, что осуществляется путем создания ссылки на каталог (directory link). Сделать это можно с помощью команды ln <N> undel_file_name, где undel_file_name — имя, которое будет дано файлу после восстановления (при необходимости имя восстанавливаемого файла указывается с полным путем).

Внимание!

Создание ссылок на каталог необратимо затирает оригинальные имена удаленных файлов.

После присвоения имени восстановленному файлу полезно дать команду dirty, чтобы файловая система была автоматически проверена при следующей загрузке. Как вариант, можно выйти из отладчика и вручную запустить команду fsck с ключом -f, форсирующим проверку.

Теперь перейдем к восстановлению оригинального имени. Рассмотрим простейший случай, когда каталог, содержащий удаленный файл (также называемый родительским каталогом), все еще цел. В этом случае следует дать команду stat dir_name и запомнить номер inode, возвращенный этой командой.

Затем следует дать отладчику команду dump <INODE> dir_file, где INODE — номер сообщенного индексного дескриптора, a dir_file — имя файла "родной" файловой системы, в которую будет записан дамп. Полученный дамп следует загрузить в шестнадцатеричный редактор и просмотреть его содержимое в "сыром" виде. Все имена будут там. При желании можно написать утилиту-фильтр, выводящую только удаленные имена. На Perl это не замет и десяти минут.

А как быть, если родительский каталог тоже удален? В этом случае и он будет помечен как удаленный! Выводим список удаленных индексных дескрипторов, выбираем из этого списка каталоги, формируем перечень принадлежащих им блоков и сохраняем дамп в файл, который затем следует просмотреть вручную или с помощью утилиты-фильтра. Как уже отмечалось, порядок расположения файлов в inode очень часто совпадает с порядком расположения файлов в каталоге, поэтому восстановление оригинальных имен в четырех случаях из пяти проходит на ура.

При тяжких разрушениях, когда восстанавливаемый файл приходится собирать по кусочкам, помогает команда dump_unused, выводящая на терминал все неиспользуемые блоки. Имеет смысл перенаправить вывод в файл, запустить hexedit и покопаться в этой куче хлама — это, по крайней мере, проще, чем искать по всему диску. На дисках, заполненных более, чем на три четверти, этот трюк сокращает массу времени.

Таким образом, можно сделать вывод о том, что отладчик debugfs в значительной мере автоматизирует восстановление удаленных файлов, однако восстановить файл с разрушенным inode он не способен, и без lde в данном случае не обойтись.

Восстановление удаленных файлов с помощью утилиты R-Studio

Утилита R-Studio for NTFS, вопреки своему названию, поддерживает не только NTFS, но и файловые системы ext2fs/ext3fs (рис. 8.7). С точки зрения обычных пользователей, это — хорошее средство для автоматического восстановления удаленных файлов. Утилита предоставляет интуитивно-понятный интерфейс, проста в управлении и в благоприятных ситуациях позволяет восстанавливать удаленные файлы несколькими щелчками мыши. К недостаткам R-Studio for NTFS можно отнести:

? отсутствие гарантий на восстановление файлов;

? невозможность восстановления имен удаленных файлов;

? отсутствие поддержки ручного восстановления;

? невозможность восстановления файлов с разрушенным inode, несмотря на то, что под ext2fs этого можно добиться достаточно простым путем.


Рис. 8.7. Утилита R-Studio for NTFS восстанавливает удаленные файлы на разделе ext2fs. К сожалению, имена удаленных файлов не восстанавливаются

Обобщая, можно сказать, для профессионального использования R-Studio катастрофически не подходит.

Оглавление книги


Генерация: 1.261. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз