Обратный поиск inode/ файла со смещения в raw-устройстве на linux и ext3/4?
В Linux, с учетом смещения на устройство с необработанным диском, возможно ли отобразить обратно на раздел + inode?
Например, предположим, я знаю, что строка "xyz" содержится со смещением байтов 1000000 в /dev/sda: (например, xxd -l 100 -s 1000000 /dev/sda показывает дамп, который начинается с "xyz")
1) Как определить, в каком разделе (если есть) смещение 1000000 находится?(Я полагаю, это легко, но я включаю его для полноты)
2) Предполагая, что смещение находится в разделе, как мне узнать, к какому индексу он принадлежит (или определить, что оно является частью свободного пространства)? Предположительно, это зависит от конкретной файловой системы, и в этом случае кто-нибудь знает, как это сделать для ext4 и ext3?
3 ответа
Мне просто нужно было сделать нечто подобное, поэтому я решил поделиться своим решением.
Вы можете увидеть, какому разделу принадлежит смещение байта диска, проверив элементы 'offset' и 'size' в выводе udisks --show-info; например
user@host:~$ sudo udisks --show-info /dev/sda1 | grep -i 'offset'
offset: 1048576
alignment offset: 0
Вычтите это смещение из смещения диска, чтобы получить смещение байта в раздел. Таким образом, смещение диска (10000000) в /dev/sda равно смещению раздела (10000000 - 1048576) = 8951424 в /dev/sda1
Вы можете узнать, какие большие блоки находятся в разделе, используя следующую команду:
user@host:~$ sudo tune2fs -l /dev/sda1 | grep -i 'block size'
Block size: 4096
Разделите смещение байта разделения на размер блока, чтобы определить смещение блока, в этом случае 8951424 / 4096 = 2185
Выполните следующую команду, чтобы узнать, какой inode занимает этот блок:
user@host:~$ sudo debugfs -R "icheck 2185" /dev/sda1
debugfs 1.41.11 (14-Mar-2010)
Block Inode number
2185 123456
затем следующая команда, чтобы узнать, какое имя файла для этого inode:
user@host:~$ sudo debugfs -R "ncheck 123456" /dev/sda1
debugfs 1.41.11 (14-Mar-2010)
Inode Pathname
123456 /tmp/some-filename.txt
Более подробное описание того, как это можно найти на http://www.randomnoun.com/wp/2013/09/12/determining-the-file-at-a-specific-vmdk-offset
Ответ Грега Нокса правильный, но может быть проще. Я написал скрипт оболочки, lba2file, который выполняет всю арифметику для вас, исходный код ниже.
Пример использования lba2file
Решение проблемы, поставленной в вопросе (адрес указан в байтах):
kremvax$ sudo lba2file -b 1000000 /dev/sda
Disk Byte 1000000 is at filesystem block 124744 in /dev/sda1
Block is used by inode 21762939
Searching for filename(s)...
Inode Pathname
21762939 /home/lilnjn/backups/adhumbla_pics_2.zip
Пример использования с SMART
Если на вашем жестком диске поврежден сектор, вы можете узнать, какой файл поврежден, прежде чем переназначить сектор, записав в него нули. Вы можете сделать это легко, используя smartctl
а также lba2file
,
kremvax$ sudo smartctl -C -t short /dev/sdd
kremvax$ sudo smartctl -a /dev/sdd | grep '^# 1'
# 1 Short captive Completed: read failure 90% 20444 1218783739
Обратите внимание, что последний номер 1218783739
адрес диска в блоках, а не в байтах:
kremvax$ sudo lba2file 1218783739 /dev/sdd
Disk Sector 1218783739 is at filesystem block 152347711 in /dev/sdd1
Block is used by inode 31219834
Searching for filename(s)...
Inode Pathname
31219834 /home/mryuk/2020-11-03-3045-us-la-msy.jpg
31219834 /home/mryuk/web/2020-11-03-3045-us-la-msy.jpg
обсуждение
Обратите внимание, что мой скрипт по умолчанию имеет адрес сектора (часто называемый "LBA"), а не байты. Это потому, что LBA - это то, что инструменты smartctl
сообщит о наличии плохого блока на диске. Однако, если вы хотите указать байты вместо секторов, просто укажите -b
флаг.
Исходный код
Вырезать и вставить в файл или нажмите здесь, чтобы загрузить с https://github.com/hackerb9/lba2file/
#!/bin/bash
# lba2file: Given an LBA number and a drive in /dev/, print which
# filename(s), if any, use that sector.
# This is the opposite of `hdparm --fibmap /foo/bar`
# B9 Feburary 2019
if [[ "$1" == "-b" ]]; then
BYTESFLAG=Byte
shift
fi
if [[ $# -lt 2 ]]; then
echo "Usage: lba2file [-b] <sector number> /dev/sdX"
echo " -b: Use byte address instead of sector"
exit 1
fi
lba=$1
drive=$2
for partition in ${drive}?; do
info=$(udisks --show-info $partition)
if ! e2blocksize=$(tune2fs -l $partition 2>/dev/null |
grep '^Block size' | egrep -o '[0-9]+'); then
continue # Not an Ext2/3/4 partition
fi
offset=$(grep '^ offset:' <<< "$info" | egrep -o '[0-9]+')
partitionsize=$(grep '^ size:' <<< "$info" | egrep -o '[0-9]+')
diskblocksize=$(grep '^ block size:' <<< "$info" | egrep -o '[0-9]+')
# Typically: e2blocksize==4096, diskblocksize==512
# Example: offset=1048576, partitionsize=640133980160
if [[ -z "$BYTESFLAG" ]]; then
byteaddress=$((lba * diskblocksize))
else
byteaddress=$lba
fi
if [[ $byteaddress -lt $offset ||
$byteaddress -ge $((offset+partitionsize)) ]]; then
echo "Not in $partition"
continue # Not in this partition
fi
# Shift to byteaddress within partition
partitionbyteaddress=$((byteaddress - offset))
# Scale address by filesystem blocksize to find filesystem block number
e2blockaddress=$((partitionbyteaddress / e2blocksize))
Sector=${BYTESFLAG:-Sector}
echo "$Sector $lba is at filesystem block $e2blockaddress in $partition"
inode=$(debugfs -R "icheck $e2blockaddress" $partition 2>/dev/null |
tail -1 | cut -f2)
if [[ "$inode" && "$inode" != "<block not found>" ]]; then
echo "$Sector is used by inode $inode"
echo "Searching for filename(s)..."
debugfs -R "ncheck $inode" $partition 2>/dev/null
else
echo "$Sector is not in use."
fi
done
Сценарий можно доработать до однострочника:
sudo tune2fs -l /dev/<disk> \
| grep '^Block size:' \
| sed 's/.* //' \
| xargs expr '(' <LBA> '*' 512 - <partition offset in bytes> ')' / \
| sudo xargs -I{} debugfs -R 'icheck {}' /dev/<partition>
sudo debugfs -R 'ncheck <inode from prev commend>' /dev/<partition>
Но вам также может потребоваться дополнительное сопоставление при использовании LVM.