Восстановление данных. Практическое руководство
Последовательность обновления
Будучи очень важными компонентами файловой системы,
,$MFT
иINDEX
нуждаются в механизме контроля целостности своего содержимого. Традиционно для этого используются коды обнаружения и коррекции ошибок (ECC/EDC codes). Однако на тот момент, когда проектировалась NTFS, процессоры были не настолько быстрыми, как теперь, и расчет корректирующих кодов занимал значительное время, существенно снижающее производительность файловой системы. Именно поэтому от использования корректирующих кодов пришлось отказаться. Вместо них разработчики NTFS применили так называемые последовательности обновления (update sequences), также называемые fix-ups.$LogFile
В конец каждого из секторов, слагающих файловую запись (
,INDEX Record
илиRCRD Record
), записывается специальный 16-байтный номер последовательности обновления (update sequence number), дублируемый в заголовке файловой записи. При каждой операции чтения два последних байта сектора сверяются с соответствующим полем заголовка и, если драйвер NTFS обнаруживает расхождение, данная файловая запись считается недействительной.RSTR Record
Основное назначение последовательностей обновления — защита от "обрыва записи". Если в процессе записи сектора на диск исчезнет питающее напряжение, может случиться так, что часть файловой записи будет записана успешно, а другая часть — сохранит прежнее содержимое (файловая запись, как мы помним, обычно состоит из двух секторов). После восстановления питания драйвер файловой системы не может уверенно определить, была ли файловая запись записана целиком. Вот тут-то последовательности обновления и выручают! При каждой перезаписи сектора последовательность обновления увеличивается на единицу. Потому, если произошел обрыв записи, значение последовательности обновления, находящейся в заголовке файловой записи, не совпадет с последовательностью обновления, расположенной в конце сектора.
Оригинальное содержимое, расположенное "под" последовательностью обновления, хранится в специальном массиве обновления (update sequence array), расположенном в заголовке файловой записи непосредственно за концом смещения последовательности обновления (update sequence number). Для восстановления файловой записи в исходный вид необходимо извлечь из заголовка указатель на смещение последовательности обновления (он хранится по смещению 04h байт от начала заголовка) и сверить лежащее по этому адресу 16-байтное значение с последним словом каждого из секторов, слагающих файловую запись (
,INDEX Record
илиRCRD Record
). Если они не совпадут, значит, соответствующая структура данных повреждена. Использовать такие структуры следует очень осторожно (на первых порах лучше не использовать вообще).RSTR Record
По смещению
от начала сектора находится 16-разрядное поле, хранящее совокупный размер номера последовательности обновления вместе с массивом последовательности обновления (006h
), выраженный в словах (не в байтах!). Так как размер номера последовательности обновления всегда равен одному слову, то размер массива последовательности обновления, выраженный в байтах, должен вычисляться следующим образом: (sizeof (update sequence number) + sizeof(update sequence array)
. Таким образом, смещение массива оригинального содержимого равно:update sequence number & update sequence array - 1)*2
. В Windows NT и Windows 2000 номер последовательности обновления всегда располагается по смещению(offset to update sequence number) + 2
от начала заголовка файловой записи или индексного заголовка, а поле2Ah
— по смещениюupdate sequence array
. В Windows XP и более новых операционных системах эти значения располагаются по смещениям2Ch
и2Dh
соответственно.2Fh
Первое слово массива последовательности обновления соответствует последнему слову первого сектора файловой записи или индексной записи. Второе — последнему слову второго сектора и т.д. Для восстановления сектора в исходный вид необходимо вернуть все элементы массива последовательности обновления на их законные места (естественно, модифицируется не сам сектор, а его копия в памяти).
Чтобы проиллюстрировать сказанное выше, рассмотрим пример, приведенный в листинге 6.2.
Листинг 6.2. Оригинальная файловая запись до восстановления
--> начало первого сектора FILE Record
00000000: 46 49 4C 45-<b>2A 00 03 00</b>-7C 77 1A 04-02 00 00 00 FILE*...|w......
00000010: 01 00 02 00-30 00 01 00-28 02 00 00-00 04 00 00 ....0...(.......
00000020: 00 00 00 00-00 00 00 00-06 00 <b>06 00-00 00 47 11</b> ..............G.
...
000001F0: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 06 00 ................
<-- конец первого сектора FILE Record
...
000003F0: 07 СС E1 0D-00 09 00 00-FF FF FF FF-82 79 <i>06 00</i> .Іа..... Вy..
<-- конец второго сектора FILE Record
Сигнатура
указывает на начало файловой записи, следовательно, по смещениюFILE
байт будет расположен 16-разрядный указатель на номер последовательности обновления. В данном случае он равен04h
. Очень хорошо! Переходим по смещению002Ah
и видим, что здесь лежит слово002Ah
. Перемещаемся в конец сектора и сверяем его с последними двумя байтами. Как и предполагалось, они совпадают. Повторяем ту же самую операцию со следующим сектором. Собственно говоря, количество секторов может и не равняться двум. Чтобы не гадать на кофейной гуще, необходимо извлечь 16-разрядное значение, расположенное по смещению0006h
от начала файловой записи (в данном случае оно равно06h
) и вычесть из него единицу. Действительно, получается два (сектора).0003h
Теперь нам необходимо найти массив последовательности обновления, хранящий оригинальное значение последнего слова каждого из секторов. Смещение массива обновления равно значению указателя на последовательность обновления увеличенной на два, т.е. в данном случае
. Извлекаем первое слово (в данном случае равное002Ah + 02h == 002Ch
) и записываем его в конец первого сектора. Извлекаем следующее слово (00h 00h
) и записываем его в конец второго сектора.47h 11h
В результате восстановленный сектор будет выглядеть, как показано в листинге 6.3.
Листинг 6.3. Восстановленная файловая запись
--> Начало первого сектора файловой записи