Ответ Грега Нокса правильный, но может быть проще. Я написал скрипт оболочки, 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