101 lines
3.7 KiB
Python
101 lines
3.7 KiB
Python
CHUNK = 128*512
|
|
LV_START = 5120000*512
|
|
BSIZE = 4096
|
|
|
|
# We know block 9262 is the root directory data block
|
|
# and it reads correctly. Let's find its chunk position.
|
|
known_virt = 9262 * BSIZE
|
|
group = known_virt // (5*CHUNK)
|
|
in_group = known_virt % (5*CHUNK)
|
|
chunk_idx = in_group // CHUNK
|
|
intra = in_group % CHUNK
|
|
|
|
print(f'Root dir block 9262: chunk_group={group} chunk_idx={chunk_idx}')
|
|
|
|
# Now check the 5th chunk in the SAME group
|
|
meta_virt = group * 5 * CHUNK + 4 * CHUNK
|
|
print(f'5th chunk in same group at phys byte: {LV_START + meta_virt}')
|
|
|
|
# Read 512 bytes from the 5th chunk
|
|
with open('/dev/md0','rb') as f:
|
|
f.seek(LV_START + meta_virt)
|
|
data = f.read(512)
|
|
print(f'First 64 bytes: {data[:64].hex()}')
|
|
print()
|
|
|
|
# Compare with what we read from the PERC metadata chunk earlier
|
|
# istat showed volumes dir data at block 5251104 (chunk_idx=4)
|
|
# Let's check if that block's data might actually be at a different
|
|
# physical location - maybe the PERC remapped it
|
|
|
|
# What if for chunk_idx=4, the data is stored in a DIFFERENT disk's
|
|
# corresponding chunk? i.e. the PERC uses the 5th physical chunk
|
|
# on a different disk?
|
|
|
|
# Our disk order: sda(0) sde(1) sdd(2) sdc(3)
|
|
# In RAID0: chunk N goes to disk N%4
|
|
# For a group of 5 virtual chunks:
|
|
# virtual chunk 0 -> disk 0
|
|
# virtual chunk 1 -> disk 1
|
|
# virtual chunk 2 -> disk 2
|
|
# virtual chunk 3 -> disk 3
|
|
# virtual chunk 4 -> ??? (metadata chunk - no disk?)
|
|
|
|
# BUT: if the physical layout has 5 chunks per group across 4 disks
|
|
# maybe it's: disk0 gets chunks 0,4 / disk1 gets chunk1 / etc?
|
|
# Or maybe all 5 chunks exist on disk but chunk 4 is PERC metadata
|
|
# that happens to occupy the same space as filesystem data?
|
|
|
|
# The PERC sector-level metadata we found earlier:
|
|
# Each 64KB metadata chunk stores 512 bytes per sector of the adjacent data
|
|
# That's 128 sectors * 512 bytes = 64KB of per-sector checksums/metadata
|
|
# So the 5th chunk IS pure PERC internal data, not filesystem data
|
|
|
|
# This means: filesystem block 5251104 maps to virtual chunk_idx=4
|
|
# BUT the actual filesystem data for that block must be stored differently
|
|
# OR the block number in the inode is a VIRTUAL block number
|
|
# that the PERC translates differently than we think
|
|
|
|
# Let's check: what if block numbers in inodes are PERC virtual block numbers?
|
|
# PERC virtual block 5251104:
|
|
# In PERC virtual space (5 chunks per group):
|
|
# group = 5251104*4096 // (5*CHUNK) = ?
|
|
perc_virt_byte = 5251104 * BSIZE
|
|
perc_group = perc_virt_byte // (5*CHUNK)
|
|
perc_in_group = perc_virt_byte % (5*CHUNK)
|
|
perc_chunk_idx = perc_in_group // CHUNK
|
|
perc_intra = perc_in_group % CHUNK
|
|
|
|
print(f'If block 5251104 is PERC virtual:')
|
|
print(f' PERC group={perc_group} chunk_idx={perc_chunk_idx} intra={perc_intra}')
|
|
|
|
# And the physical location would be:
|
|
# physical = LV_START + perc_group*4*CHUNK + perc_chunk_idx*CHUNK + perc_intra
|
|
if perc_chunk_idx != 4:
|
|
phys = LV_START + perc_group*4*CHUNK + perc_chunk_idx*CHUNK + perc_intra
|
|
print(f' Physical byte: {phys}')
|
|
with open('/dev/md0','rb') as f:
|
|
f.seek(phys)
|
|
data = f.read(BSIZE)
|
|
nonzero = sum(1 for b in data if b != 0)
|
|
print(f' Nonzero: {nonzero}/4096')
|
|
print(f' First 32: {data[:32].hex()}')
|
|
|
|
# Try to parse as directory
|
|
import struct
|
|
off = 0
|
|
print(' Directory entries:')
|
|
while off < BSIZE-8:
|
|
ino = struct.unpack_from('<I', data, off)[0]
|
|
rec_len = struct.unpack_from('<H', data, off+4)[0]
|
|
name_len= data[off+6]
|
|
ftype = data[off+7]
|
|
if rec_len < 8: break
|
|
if ino > 0 and name_len > 0:
|
|
name = data[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
|
tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
|
|
print(f' {tname} inode={ino} {name!r}')
|
|
off += rec_len
|
|
else:
|
|
print(f' Still in metadata chunk!')
|