Эта часть может быть очень легкой и довольно сложной, в зависимости от того, занимал ли удаленный файл больше 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 следующим образом размещается информация о блоках с данными файла:
Номера первых 12 блоков хранятся непосредственно в inode; их еще иногда называют блоками с прямой адресацией (direct blocks).
В inode хранится номер блока, в котором хранятся номера еще 256 блоков данных. Иногда его называют блок косвенной адресации (indirect block).
В inode хранится номер блока, в котором хранятся 256 номеров блоков косвенной адресации. Иногда этот блок называют блоком двойной косвенной адресации (doubly indirect block).
В inode хранится номер блока, в котором хранятся 256 номеров блоков двойной косвенной адресации. Его называют блоком тройной косвенной адресации (triply indirect block).
Прочтите еще раз: я знаю, что это непросто, но также и очень важно.
Версии ядра до 2.0.36 включительно при удалении файла обнуляют блоки косвенной адресации (а также блоки двойной косвенной адресации и т. д.). Так что если ваш файл был длинной более 12 блоков, нет никакой гарантии, что вы сможете выявить даже номера блоков с данными, не говоря уже о самих данных.
Единственный способ, который я нашел - это предположить, что файл не был фрагментирован; если был, то у вас проблемы. Если же предполагать, что файл не был фрагментирован, то, в зависимости от количества блоков с данными файла, возможно следующее расположение блоков, описывающих местоположение файла:
Номера блоков хранятся в inode, как описано выше.
После блоков с прямой адресацией идет блок косвенной адресации и далее 256 блоков с данными.
Как и в прошлом случае, в начале 12 блоков с прямой адресацией, блок косвенной адресации и 256 блоков данных. Далее блок двойной косвенной адресации, за ним 256 групп блоков, состоящих из одного блока косвенной адресации и 256 блоков данных.
Расположение первых 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 |
В результате, если нам повезло, то файл полностью восстановлен.