Linuxでは、rawディスクデバイスへのオフセットが与えられた場合、パーティション+ iノードにマップバックすることは可能ですか?
たとえば、文字列「xyz」が/ dev/sdaのバイトオフセット1000000に含まれていることがわかっているとします(たとえば、xxd -l 100 -s 1000000/dev/sdaは「xyz」で始まるダンプを示します)
1)オフセット1000000がどのパーティション(存在する場合)にあるかをどのように把握しますか?(これは簡単だと思いますが、完全を期すために含めています)
2)オフセットがパーティションにあると仮定すると、オフセットが属するiノードを見つける(または空き領域の一部であると判断する)にはどうすればよいですか?おそらくこれはファイルシステム固有のものですが、その場合、ext4とext3でこれを行う方法を知っている人はいますか?
私は同じようなことをしなければならなかったので、私は自分の解決策を共有したいと思いました。
Udisks --show-info出力の「offset」要素と「size」要素をチェックすることで、ドライブのバイトオフセットがどのパーティションに属しているかを確認できます。例えば.
user@Host:~$ Sudo udisks --show-info /dev/sda1 | grep -i 'offset'
offset: 1048576
alignment offset: 0
ディスクオフセットからこのオフセットを減算して、バイトオフセットをパーティションに取り込みます。したがって、/ dev/sdaのディスクオフセット(10000000)は、/ dev/sda1のパーティションオフセット(10000000-1048576)= 8951424です。
次のコマンドを使用して、パーティション内のブロックの大きさを確認できます。
user@Host:~$ Sudo tune2fs -l /dev/sda1 | grep -i 'block size'
Block size: 4096
パーティションのバイトオフセットをブロックサイズで除算して、ブロックオフセットを決定します。この場合は8951424/4096 = 2185
次のコマンドを実行して、そのブロックを占めるiノードを確認します。
user@Host:~$ Sudo debugfs -R "icheck 2185" /dev/sda1
debugfs 1.41.11 (14-Mar-2010)
Block Inode number
2185 123456
次に、次のコマンドを使用して、そのiノードのファイル名を確認します。
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 を作成しました。
質問で提起された問題の解決(アドレスをバイト単位で指定):
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
ハードドライブに不良セクタがある場合は、セクタにゼロを書き込んで再マッピングする前に、破損しているファイルを確認することをお勧めします。 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」と呼ばれることが多い)になっていることに注意してください。これは、ドライブに不良ブロックがある場合にsmartctl
などのツールが報告するのはLBAであるためです。ただし、セクターではなくバイトを指定する場合は、-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