Разгребая кластерные обломки
Рассмотрим более сложный случай восстановления, когда файловая запись уже затерта. Если удаленный файл был резидентным (т.е. хранил свое тело в MFT), то восстанавливать уже нечего. Даже если на его месте создан нерезидентный файл (а файловая запись нерезидентного файла заканчивается там, где начинается резидентное тело), операционная система заботливо заполнит оставшийся "хвост" нулями и для восстановления оригинального содержимого придется прибегнуть к дорогостоящему оборудованию, читающему поверхность "блинов" жесткого диска на физическом уровне.
С нерезидентными файлами, хранящими свое тело вне MFT, ситуация обстоит не так плачевно, хотя проблем тоже хватает. Порядок размещения файла на диске хранится в run-list'e внутри файловой записи в MFT (теперь уже затертой) и потому, возможен лишь контекстный поиск по содержимому. Запускаем диск-редактор, вводим последовательность, заведомо содержащуюся в удаленном файле, но не встречающуюся во всех остальных и нажимаем "search". Для ускорения поиска можно искать только в свободном дисковом пространстве (за это отвечает файл /$BITMAP). Известные мне редакторы пренебрегают этой возможностью (а зря!), однако, утилиту "продвинутого" поиска несложно написать и самостоятельно.
Нефрагментированные файлы восстанавливаются элементарно. Просто выделяем группу секторов и записываем ее на диск (только ни в коем случае не на сам восстанавливаемый том!). Единственная проблема – как определить оригинальную длину? Некоторые типы файлов допускают присутствие "мусора" в своем хвосте (и тогда нам остается следовать правилу "лучше перебрать, чем недобрать"), а некоторые нет! Если конец не удается определить визуально (например, pdf-файлы завершаются сигнатурой "%%EOF"), проанализируйте заголовок файла – среди прочей полезной информации обычно там присутствует и его размер. Тут все зависит от структуры конкретного файла и универсальных рекомендаций дать невозможно.
Если файл фрагментирован – дело намного хуже. Ситуация практически безнадежна, поскольку, чтобы собрать разрозненные цепочки кластеров воедино, необходимо хорошо знать содержимое удаленного файла. В этом смысле, NTFS восстанавливается намного хуже, чем FAT. Последовательность фрагментов файла, хранящаяся в File Allocation Table в виде однонаправленного списка очень живуча. Если список не поврежден, достаточно лишь найти его первый элемент (а сделать это проще простого, поскольку он будет указывать на заголовок файла с вполне предсказуемым содержимым). Даже если список "разрубить" на несколько частей, они продолжать жить собственной жизнью и нам останется лишь подобрать комбинацию как их правильно склеить воедино. Список гибнет лишь при полном затирании FTA'а, что случается прямо скажем не часто. В NTFS же порядок фрагментов файла хранится в крохотных списках отрезков и их гибель – обычное дело, после чего мы остается один на один с миллионом беспорядочно разбросанных кластеров. С текстовыми файлами еще куда бы то ни шло, но что делать, если это электронная таблица, графическое изображение или архив какой? Без знания стратегии выделения дискового пространства здесь никуда. Порядок, в котором драйвер файловой системы находит подходящие свободные фрагменты, не определен и варьируется в зависимости от множества обстоятельств, однако, кое-какие закономерности в нем все же присутствуют.
Анализируя списки отрезков сильно фрагментированных дисков мне удалось установить следующее: сначала заполняются самые большие "дыры", двигаясь от конца MFT-зоны к концу диска. Затем, драйвер файловой системы возвращается назад и начинает заполнять дыры поменьше и так продолжается до тех пор, пока файл не оказывается на диске целиком. Последними заполняются дыры размером в один кластер. Просматривая карту диска, представленную файлом /$BITMAP, мы можем в точности восстановить порядок размещения фрагментов удаленного файла, наскоро собрав их воедино. Во всяком случае, теоретически. Практически же на этом пути нас ждут коварные препятствия. С момента создания восстанавливаемого файла карта свободного дискового пространства могла капитально преобразиться. Всякое удаление файлов высвобождает одну или несколько дыр, хаотично перемешивающихся с дырами восстанавливаемого файла, искажая картину. Как этому противостоять? Сканируем MFT в поисках записей, помеченных как удаленные, но еще не затертых. Декодируем run-list'ы и вычеркиваем соответствующие им фрагменты из списка кандидатов на восстановление. Это существенно сужает круг поиска, хотя количество комбинаций в которые можно собрать фрагментированный файл по-прежнему остается велико. Но это еще что…
Самое "интересное" начинается, когда на диск одновременно записываются несколько файлов (например, скачиваемых ReGet'ом из Интернета) или файл постепенно увеличивает свой размер (набираете дипломную работу в Word'е?), а в это время на диск записываются другие файлы. Когда к существующему файлу дописывается крошечная порция данных, файловая система находит наименьшую дыру, затем следующую наименьшую дыру и т. д., вплоть до тех пор пока маленькие дыры не исчерпаются и тогда наступает черед дыр побольше. Как следствие, файл выходит сильно фрагментированным – это раз. Файл заполняется не от больших дыр к меньшим, а наоборот (т. е. происходит инверсия стратегии размещения) – это два. Маленькие фрагменты одного файла перемешиваются с маленькими фрагментами других файлов – это три.
Хуже всего поддаются восстановлению документы, созданные в MS Office и вот почему: приложение создает большое количество резервных копий редактируемого файла, как в текущем каталоге, так и в каталоге %TEMP%. Вот и разберись какой фрагмент какому файлу принадлежит!
Проще всего восстанавливаться ZIP-архивы. Для этого вам даже не потребуется запускать дисковый редактор. Откройте временный файл на запись, сделайте seek на размер свободного дискового пространства, закройте файл. А теперь обработайте его утилитой pkzipfix.exe (или запустите стандартный pkzip.exe с ключом Fix). В "исправленном" файле волшебным образом появятся все уцелевшие ZIP-архивы! Внутренняя структура ZIP-архива такова, что pkzipfix легко распознает даже переупорядоченные блоки, поэтому высокая степень фрагментации ему не помеха.
Дефрагментация тоже происходит интересно. Стандартное API дефрагментации в силу малопонятных ограничений оперирует не единичными кластерами, а блоками! Минимальный размер блока составляет 16 кластеров, причем начало блока должно быть кратно 16 кластерам в файле! Как следствие – количество мелких дыр после дефрагментации только возрастает, а непрерывных областей свободного пространства практически совсем не остается. Кстати говоря, перемещать внутрь MFT-зоны тоже ничего нельзя. "На томе С: свободно 17%, но только 5% доступно для использования дефргаментатора диска. Для эффективной работы дефрагментатор требует по крайней мере 15% доступного свободного места" – знакомое сообщение, не правда ли? "Недоступное" для дефрагментатора место находится внутри MFT-зоны (как мы помним, при форматировании диска под $MFT-файл резервируется 10% от емкости тома, а затем по мере исчерпания дискового пространства, $MFT-файл усекается наполовину и освободившееся пространство заселяется пользовательскими файлами). Таким образом, для гарантированной работы дефргаментатора ему нужно 10% + 15% == 25% свободного дискового пространства. Не слишком ли высокая плата за дефргаментацию? Если же у вас свободно свыше 25%, настоятельно рекомендуется создать на диске временный файл и выполнить seek, чтобы заполнить все более или менее крупные дыры, не давая их изородовать дефрагментатору (естественно, после дефрагментации этот файл нужно удалить). Кстати говоря, на сжатые файлы ограничение в 16 кластеров не распространяется, поэтому мелкие файлы очень выгодно держать в сжатом состоянии – это существенно уменьшает фрагменацию тома. Почаще дефрагментируйте свой диск! Это не только увеличит быстродействие, но и упростит восстановление удаленных файлов с затертой FILE Record.