#!/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 May 2020 if [[ "$1" == "-b" ]]; then BYTESFLAG=Byte shift fi if [[ $# -lt 2 ]]; then echo "Usage: lba2file [-b] /dev/sdX" echo " -b: Use byte address instead of sector" exit 1 fi if [[ $(id -u) -ne 0 ]]; then echo "Please run as root using 'sudo $@'" >&2 exit 1 fi lba=$1 drive=$2 drive=${drive#/dev/} # Remove /dev/ prefix, if any. if [[ "$drive" =~ ^(.*)[0-9]$ ]]; then # Either user specified a partition. searchparts="/sys/class/block/$drive" drive=${BASH_REMATCH[1]} else # Or user specified a drive. shopt -s nullglob # Don't use '?' literally. searchparts=$(eval echo /sys/class/block/${drive}?) fi for partition in $searchparts; do device=/dev/${partition#/sys/class/block/} cd "$partition" || continue start=$(cat "$partition/start") partitionsize=$(cat "$partition/size") hwsectorsize=$(cat "/sys/class/block/$drive/queue/hw_sector_size") # Typically: e2blocksize==4096, hwsectorsize==512 # Example: start=1048576, partitionsize=640133980160 # Do a sanity check. if [[ -z "$start" || -z "$partitionsize" || -z "$hwsectorsize" ]]; then echo "Error reading data for $device" >&2 continue fi # Scale everything to bytes since we'll use that for debugfs. start=$((start * hwsectorsize)) partitionsize=$((partitionsize * hwsectorsize)) # If not using byte flag, scale the address, too. if [[ -z "$BYTESFLAG" ]]; then byteaddress=$((lba * hwsectorsize)) else byteaddress=$lba fi if [[ $byteaddress -lt $start || $byteaddress -ge $((start+partitionsize)) ]]; then #echo "Address $byteaddress is not within $partition" continue # Not in this partition fi if ! e2blocksize=$(tune2fs -l $device 2>/dev/null | grep '^Block size' | egrep -o '[0-9]+'); then echo "Skipping $device, not an Ext2/3/4 partition" continue fi # Scale address by filesystem blocksize to find filesystem block number e2blockaddress=$(( (byteaddress - start) / e2blocksize)) Sector=${BYTESFLAG:-Sector} echo "Disk $Sector $lba is at filesystem block $e2blockaddress in $device" inode=$(debugfs -R "icheck $e2blockaddress" $device 2>/dev/null | tail -1 | cut -f2) if [[ "$inode" && "$inode" != "" ]]; then echo "$Sector is used by inode $inode" echo "Searching for filename(s)..." debugfs -R "ncheck $inode" $device 2>/dev/null else echo "$Sector is not in use." fi done