Как происходит удаление файла
В общих чертах процедура удаления (разлинковки) файла выглядит следующим образом. Драйвер файловой системы определяет каталог, за которым закреплен удаляемый файл и находит inode файла в последовательности структур типа ext2_dir_entry_2. После чего отыскивает нужный inode в inode-таблице и уменьшает его счетчик ссылок (i_links_count) на единицу. Если счетчик не становится равен нулю, удаления не происходит (ссылка на файл могла остаться в другом каталоге); в противном случае – пишите письма, драйвер приступает к грязной работе. Все принадлежащие файлу блоки помечаются как неиспользуемые в карте свободного пространства. Обновляется поле времени удаления, и inode освобождается. В конце концов, драйвер обнуляет поле inode файла в файле каталога и увеличивает длину предыдущей записи на размер удаляемой (именно для этого нужно поле rec_len).
Нетрудно заметить, что фактического удаления информации не происходит. Более того, inode файла остается на месте и продолжает хранить всю информацию об удаленном файле. Ссылки на блоки данных также остаются на месте, но сами блоки помечаются как неиспользуемые, что дает право другим файлам использовать их для хранения своей информации. Освобождается и сам inode, но опасность его повторного использования другим файлом очень низка в силу большого резерва файловых дескрипторов, которые будут задействованы в первую очередь. Получается, что для восстановления удаленного файла в файловой системе ext2 достаточно узнать номер его inode, прочитать и распутать вереницу массивов ссылок на блоки данных, а затем собрать из них файл!
С файловой системой ext3 все намного сложнее: ее драйвер очищает массив ссылок на блоки (i_block), так что файл придется собирать по кусочкам, разыскивая блоки по всей файловой системе.
В стране мертвых
Чтобы избежать перезаписи блоков удаленного файла, восстановление следует начать с немедленного размонтирования раздела. Если же файл находился на корневом разделе, лучшее средство - кнопка RESET на системном блоке и последующая загрузка с LiveCD.
Для низкоуровневой навигации по файловой системе не обязательно использовать шестнадцатеричный редактор, существует несколько утилит, которые облегчают этот процесс. Одна из них - стандартная команда debugfs из пакета e2fsprogs.
Запустите ее с указанием раздела, содержащего подопытную файловую систему:
$ debugfs /dev/sda1
Откроется командная строка, которая принимает множество команд. Наберите help, чтобы увидеть их. Наиболее интересные для нас команды: lsdel, stat, cat и dump. Команда lsdel показывает все удаленные inode:
debugfs: lsdel
Скорее всего, список будет очень длинным, поэтому лучше сразу перенаправить его в файл:
$ echo lsdel | debugfs /dev/sda1 > /tmp/lsdel.out
Откройте полученный файл и попытайтесь найти разыскиваемого по времени удаления, размеру, владельцу и другим данным. Запомните номер его inode и выполните команду stat в командной строке debugfs:
debugfs: stat <номер_inode>
На экране появится вся информация об inode (номер, тип, владелец, время создания и удаления и пр.). В конце вывода будет присутствовать информация о блоках, занимаемых файлом на диске, и их количество. На основе этих данных можно восстановить любой файл, воспользовавшись командой dd в качестве инструмента. Но есть более простой способ. Команда dump делает снимок всех блоков, принадлежащих указанному inode, и записывает их в указанный файл:
debugfs: dump -p <номер_inode> /tmp/восстановленный_файл
Ключ -p сохраняет за файлом прежние права доступа, владельца и группу. Имя файла придется подобрать по памяти, оно хранилось в каталоге и было затерто во время удаления. Если вы ищете текстовый файл, то для полной уверенности лучше сначала выполнить команду cat над inode, которая выведет содержимое файла прямо на экран:
debugfs: cat <номер_inode>
Чтобы идентифицировать файл после его восстановления, можно применить утилиты file и strings. Первая покажет тип файла, а вторая выведет на экран все читаемые строки, которые он содержит.
Для восстановления утраченных файлов необязательно делать их дамп в существующую файловую систему, - можно изменить саму inode-таблицу. Сделать это просто. Открываем дисковый раздел (или его снимок) в режиме записи:
# debugfs -w /dev/sda1
Находим описанным выше способом inode удаленного файла и открываем его на редактирование:
debugfs: mi <номер_inode>
Команда mi расшифровывается как «modify inode» и предназначена для ручного редактирования inode. Она выводит на экран все поля inode и их текущие значения, заключенные в квадратные скобки. Курсор будет останавливаться у каждого поля, ожидая ввода нового значения, которое можно пропустить, нажав <Enter>. Нас интересует только два поля: время удаления (Deletion time) и количество ссылок (Link count). Первое следует обнулить, а второму присвоить значение 1. Так мы вернем мертвый файл к жизни, но введем файловую систему в скомпрометированное состояние: файл есть, но найти его невозможно (запись каталога, содержащая его имя и ссылку на inode, уже затерта). С точки зрения файловой системы это ошибка, которая дает нам два варианта последующих действий.
Мы можем запустить fsck, который найдет несоответствия в файловой системе и исправит их, поместив наших призраков в каталог lost+found:
# e2fsck -f /dev/sda1
Или же воспользоваться методом прямого вмешательства: создать жесткую ссылку на файл, используя команду link утилиты debugfs:
debugfs: link <номер_inode> восстановленный_файл
Восстановленный файл появится в текущем каталоге. Однако команду e2fsck придется запустить и в этом случае, потому как закрепленные за файлом блоки до сих пор помечены как неиспользуемые.
