Восстановление блоков данных

Эта часть может быть очень легкой и довольно сложной, в зависимости от того, занимал ли удаленный файл больше 12 блоков или нет.

Короткие файлы

Если файл занимал не больше 12 блоков, то все их номера хранятся непосредственно в inode. Вы можете просмотреть их командой stat. Более того, debugfs имеет команду, позволяющую восстановить файл автоматически. Например:

debugfs:  stat <148003>
Inode: 148003   Type: regular    Mode:  0644   Flags: 0x0   Version: 1
User:   503   Group:   100   Size: 6065
File ACL: 0    Directory ACL: 0
Links: 0   Blockcount: 12
Fragment:  Address: 0    Number: 0    Size: 0
ctime: 0x31a9a574 -- Mon May 27 13:52:04 1996
atime: 0x31a21dd1 -- Tue May 21 20:47:29 1996
mtime: 0x313bf4d7 -- Tue Mar  5 08:01:27 1996
dtime: 0x31a9a574 -- Mon May 27 13:52:04 1996
BLOCKS:
594810 594811 594814 594815 594816 594817
TOTAL: 6

Файл занимает 6 блоков. Так как 6 меньше 12, даем команду debugfs записать файл в новое место, например /mnt/recovered.000:

debugfs:  dump <148003> /mnt/recovered.000

Также можно это сделать с помощью fsgrab. Пример:

# fsgrab -c 2 -s 594810 /dev/hda5 > /mnt/recovered.000
# fsgrab -c 4 -s 594814 /dev/hda5 >> /mnt/recovered.000

В обоих случаях (как debugfs, так и fsgrab) в конце /mnt/recovered.000 будет мусор. Впрочем, это не так уж важно. Самый простой способ убрать его - использовать значение поля Size из inode с ключом bs команды dd:

# dd count=1 if=/mnt/recovered.000 of=/mnt/resized.000 bs=6065

Конечно существует вероятность, что один или несколько блоков вашего файла были перезаписаны. Если это так, то вам не повезло - данные этого блока навсегда потеряны.

Длинные файлы

Сложнее обстоит дело с файлами длиной более 12 блоков. Необходимо пояснить, как устроена файловая система UNIX. Данные файла хранятся в так называемых "блоках". Эти блоки пронумерованы. Для каждого файла также имеется "inode" (от английского information node), где хранится информация о владельце, правах, типе файла и т. п. Также как и блоки, inode пронумерованы (хотя нумерация ведется независимо от блоков). Каталоги файловой системы содержат имя файла и номер inode.

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

Прочтите еще раз: я знаю, что это непросто, но также и очень важно.

Версии ядра до 2.0.36 включительно при удалении файла обнуляют блоки косвенной адресации (а также блоки двойной косвенной адресации и т. д.). Так что если ваш файл был длинной более 12 блоков, нет никакой гарантии, что вы сможете выявить даже номера блоков с данными, не говоря уже о самих данных.

Единственный способ, который я нашел - это предположить, что файл не был фрагментирован; если был, то у вас проблемы. Если же предполагать, что файл не был фрагментирован, то, в зависимости от количества блоков с данными файла, возможно следующее расположение блоков, описывающих местоположение файла:

0 - 12

Номера блоков хранятся в inode, как описано выше.

13 - 268

После блоков с прямой адресацией идет блок косвенной адресации и далее 256 блоков с данными.

269 - 65804

Как и в прошлом случае, в начале 12 блоков с прямой адресацией, блок косвенной адресации и 256 блоков данных. Далее блок двойной косвенной адресации, за ним 256 групп блоков, состоящих из одного блока косвенной адресации и 256 блоков данных.

65805 и более

Расположение первых 65804 блоков указано выше. Далее один блок тройной косвенной адресации и 256 повторений групп "двойной косвенной адресации". Каждая такая группа состоит из блока двойной косвенной адресации, за которым идет 256 групп из одного блока косвенной адресации и 256 блоков данных.

Даже если номера блоков данных правильны, нет никакой гарантии, что данные в них не перезаписывались. К тому же, чем больше файл, тем меньше шансов, что он был записан без фрагментации (кроме некоторых особых случаев).

Заметьте, что я предполагал, что размер вашего блока 1024 байта, так как это стандартное значение. Если ваши блоки больше, некоторые числа, указанные выше, изменятся. В частности: так как номер блока занимает 4 байта, то количество номеров блоков, которые могут быть размещены в блоке косвенной адресации равно размер_блока/4. Так что везде, где выше встречается число 256, меняйте его на размер_блока/4. Количество требуемых для размещения файла блоков также нужно изменить.

Пример восстановления длинного файла:

debugfs:  stat <1387>
Inode: 148004   Type: regular    Mode:  0644   Flags: 0x0   Version: 1
User:   503   Group:   100   Size: 1851347
File ACL: 0    Directory ACL: 0
Links: 0   Blockcount: 3616
Fragment:  Address: 0    Number: 0    Size: 0
ctime: 0x31a9a574 -- Mon May 27 13:52:04 1996
atime: 0x31a21dd1 -- Tue May 21 20:47:29 1996
mtime: 0x313bf4d7 -- Tue Mar  5 08:01:27 1996
dtime: 0x31a9a574 -- Mon May 27 13:52:04 1996
BLOCKS:
8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8583
TOTAL: 14

В данном случае шансы того, что файл не фрагментирован, довольно велики: первые 12 блоков, перечисленные в inode, (блоки с данными) идут подряд. Начнем с того, что восстановим их:

# fsgrab -c 12 -s 8314 /dev/hda5 > /mnt/recovered.001

Следующий блок указанный в inode (8326) - блок косвенной адресации, который мы можем игнорировать, так как предполагаем, что за ним идут блоки данных (с 8327 по 8582).

# fsgrab -c 256 -s 8327 /dev/hda5 >> /mnt/recovered.001

Последний блок, указанный в inode имеет номер 8583. Заметьте, если предположить, что файл не фрагментирован, то пока все нормально: последний блок данных, записанный нами имеет номер 8582, то есть 8327 + 255. Блок 8583 - блок двойной косвенной адресации, его можно игнорировать. За ним идут до 256 групп состоящих из блока косвенной адресации (который мы также игнорируем), и 256 блоков данных. Быстренько выполнив несложные арифметические подсчеты, выполняем следующие команды (заметьте, что мы пропускаем блок двойной косвенной адресации 8583 и следующий за ним (как мы надеемся) блок косвенной адресации 8584 и начинаем с блока 8525):

# fsgrab -c 256 -s 8585 /dev/hda5 >> /mnt/recovered.001
# fsgrab -c 256 -s 8842 /dev/hda5 >> /mnt/recovered.001
# fsgrab -c 256 -s 9099 /dev/hda5 >> /mnt/recovered.001
# fsgrab -c 256 -s 9356 /dev/hda5 >> /mnt/recovered.001
# fsgrab -c 256 -s 9613 /dev/hda5 >> /mnt/recovered.001
# fsgrab -c 256 -s 9870 /dev/hda5 >> /mnt/recovered.001

Итого мы записали 12 + (7 * 256) блоков, то есть 1804. В соответствие с результатом команды "stat" число блоков в файле было равно 3616; считается, что это блоки длиной 512 байт (пережиток с UNIX), поэтому, в действительности, нам надо 3616/2 = 1808 блоков длиной 1024 байт. То есть, нам нужно записать еще четыре блока. Последний записанный блок имел номер 10125. Также, как и раньше, пропускаем блок косвенной адресации (номер 10126) и записываем последние четыре блока:

# fsgrab -c 4 -s 10127 /dev/hda5 >> /mnt/recovered.001

В результате, если нам повезло, то файл полностью восстановлен.