Initial remote commit
This commit is contained in:
157
misc_tools/extant_debug.py
Normal file
157
misc_tools/extant_debug.py
Normal file
@@ -0,0 +1,157 @@
|
||||
import struct
|
||||
|
||||
CHUNK = 128*512
|
||||
LV_START = 5120000*512
|
||||
BSIZE = 4096
|
||||
IPG = 8192
|
||||
|
||||
def read_virt(virt_byte, length):
|
||||
result = bytearray(length)
|
||||
pos = virt_byte
|
||||
remaining = length
|
||||
with open('/dev/md0','rb') as f:
|
||||
while remaining > 0:
|
||||
group = pos // (5*CHUNK)
|
||||
in_group = pos % (5*CHUNK)
|
||||
chunk_idx = in_group // CHUNK
|
||||
intra = in_group % CHUNK
|
||||
seg_len = min(CHUNK-intra, remaining)
|
||||
dst_off = pos - virt_byte
|
||||
if chunk_idx != 4:
|
||||
phys = LV_START + group*4*CHUNK + chunk_idx*CHUNK + intra
|
||||
f.seek(phys)
|
||||
data = f.read(seg_len)
|
||||
result[dst_off:dst_off+len(data)] = data
|
||||
pos += seg_len
|
||||
remaining -= seg_len
|
||||
return bytes(result)
|
||||
|
||||
NUM_GROUPS = 35728
|
||||
gdt_data = read_virt(BSIZE, NUM_GROUPS*64)
|
||||
|
||||
def get_inode_table_block(group):
|
||||
entry = gdt_data[group*64:(group+1)*64]
|
||||
it_lo = struct.unpack_from('<I', entry, 8)[0]
|
||||
it_hi = struct.unpack_from('<I', entry, 40)[0]
|
||||
return (it_hi<<32)|it_lo
|
||||
|
||||
# Read /var inode raw and dump everything
|
||||
var_inode = 1310721
|
||||
group = (var_inode-1)//IPG
|
||||
idx = (var_inode-1)%IPG
|
||||
it_block = get_inode_table_block(group)
|
||||
it_virt = it_block*BSIZE + idx*256
|
||||
|
||||
print(f'/var inode {var_inode}:')
|
||||
print(f' group={group} idx={idx}')
|
||||
print(f' it_block={it_block}')
|
||||
print(f' inode virt byte={it_virt}')
|
||||
|
||||
# Check if this virtual byte is in a metadata chunk
|
||||
in_group = it_virt % (5*CHUNK)
|
||||
chunk_idx = in_group // CHUNK
|
||||
print(f' chunk_idx={chunk_idx} (4=metadata, returns zeros)')
|
||||
|
||||
inode_data = read_virt(it_virt, 256)
|
||||
print(f' raw inode: {inode_data[:64].hex()}')
|
||||
|
||||
mode = struct.unpack_from('<H', inode_data, 0)[0]
|
||||
size = struct.unpack_from('<I', inode_data, 4)[0]
|
||||
links = struct.unpack_from('<H', inode_data, 26)[0]
|
||||
mtime = struct.unpack_from('<I', inode_data, 16)[0]
|
||||
ext_magic = struct.unpack_from('<H', inode_data, 40)[0]
|
||||
eh_entries= struct.unpack_from('<H', inode_data, 42)[0]
|
||||
eh_depth = struct.unpack_from('<H', inode_data, 46)[0]
|
||||
|
||||
print(f' mode=0x{mode:04x} size={size} links={links}')
|
||||
print(f' mtime={mtime} ext_magic=0x{ext_magic:04x}')
|
||||
print(f' eh_entries={eh_entries} eh_depth={eh_depth}')
|
||||
print()
|
||||
|
||||
# Dump extent tree
|
||||
if ext_magic == 0xf30a:
|
||||
print('Extent tree:')
|
||||
if eh_depth == 0:
|
||||
for i in range(min(eh_entries,4)):
|
||||
off = 52+i*12
|
||||
ee_block = struct.unpack_from('<I', inode_data, off)[0]
|
||||
ee_len = struct.unpack_from('<H', inode_data, off+4)[0]
|
||||
ee_hi = struct.unpack_from('<H', inode_data, off+6)[0]
|
||||
ee_lo = struct.unpack_from('<I', inode_data, off+8)[0]
|
||||
ee_start = (ee_hi<<32)|ee_lo
|
||||
print(f' Extent {i}: logical={ee_block} len={ee_len} '
|
||||
f'phys_start={ee_start}')
|
||||
|
||||
# Check if this block is in a metadata chunk
|
||||
blk_virt = ee_start*BSIZE
|
||||
in_group = blk_virt % (5*CHUNK)
|
||||
chunk_idx = in_group // CHUNK
|
||||
print(f' virt_byte={blk_virt} chunk_idx={chunk_idx}')
|
||||
|
||||
# Read the block
|
||||
blk_data = read_virt(blk_virt, BSIZE)
|
||||
nonzero = sum(1 for b in blk_data if b != 0)
|
||||
print(f' nonzero bytes: {nonzero}/4096')
|
||||
print(f' first 32 bytes: {blk_data[:32].hex()}')
|
||||
|
||||
# Try to parse as directory
|
||||
off2 = 0
|
||||
count = 0
|
||||
while off2 < BSIZE-8:
|
||||
ino = struct.unpack_from('<I', blk_data, off2)[0]
|
||||
rec_len = struct.unpack_from('<H', blk_data, off2+4)[0]
|
||||
name_len= blk_data[off2+6]
|
||||
ftype = blk_data[off2+7]
|
||||
if rec_len < 8: break
|
||||
if ino > 0 and name_len > 0:
|
||||
name = blk_data[off2+8:off2+8+name_len].decode('utf-8',errors='replace')
|
||||
tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
|
||||
print(f' entry: {tname} inode={ino} {name!r}')
|
||||
count += 1
|
||||
off2 += rec_len
|
||||
if count == 0:
|
||||
print(f' No valid directory entries found')
|
||||
else:
|
||||
print(f' depth={eh_depth} - need to follow interior nodes')
|
||||
# Read interior node
|
||||
for i in range(min(eh_entries,4)):
|
||||
off = 52+i*12
|
||||
ei_block = struct.unpack_from('<I', inode_data, off)[0]
|
||||
ei_hi = struct.unpack_from('<H', inode_data, off+4)[0]
|
||||
ei_lo = struct.unpack_from('<I', inode_data, off+8)[0] # wrong offsets for idx
|
||||
# Extent index: ee_block(4) + ei_leaf_lo(4) + ei_leaf_hi(2) + unused(2)
|
||||
ei_leaf_lo = struct.unpack_from('<I', inode_data, off+4)[0]
|
||||
ei_leaf_hi = struct.unpack_from('<H', inode_data, off+8)[0]
|
||||
ei_leaf = (ei_leaf_hi<<32)|ei_leaf_lo
|
||||
print(f' Index {i}: logical={ei_block} leaf={ei_leaf}')
|
||||
|
||||
# Read the leaf block
|
||||
leaf_virt = ei_leaf*BSIZE
|
||||
leaf_data = read_virt(leaf_virt, BSIZE)
|
||||
leaf_magic = struct.unpack_from('<H', leaf_data, 0)[0]
|
||||
leaf_entries = struct.unpack_from('<H', leaf_data, 2)[0]
|
||||
leaf_depth = struct.unpack_from('<H', leaf_data, 6)[0]
|
||||
print(f' leaf magic=0x{leaf_magic:04x} entries={leaf_entries} depth={leaf_depth}')
|
||||
|
||||
if leaf_magic == 0xf30a and leaf_depth == 0:
|
||||
for j in range(min(leaf_entries,4)):
|
||||
off2 = 12+j*12
|
||||
ee_len = struct.unpack_from('<H', leaf_data, off2+4)[0]
|
||||
ee_hi = struct.unpack_from('<H', leaf_data, off2+6)[0]
|
||||
ee_lo = struct.unpack_from('<I', leaf_data, off2+8)[0]
|
||||
ee_start = (ee_hi<<32)|ee_lo
|
||||
print(f' Extent {j}: len={ee_len} start={ee_start}')
|
||||
|
||||
blk_data = read_virt(ee_start*BSIZE, BSIZE)
|
||||
off3 = 0
|
||||
while off3 < BSIZE-8:
|
||||
ino = struct.unpack_from('<I', blk_data, off3)[0]
|
||||
rec_len = struct.unpack_from('<H', blk_data, off3+4)[0]
|
||||
name_len= blk_data[off3+6]
|
||||
ftype = blk_data[off3+7]
|
||||
if rec_len < 8: break
|
||||
if ino > 0 and name_len > 0:
|
||||
name = blk_data[off3+8:off3+8+name_len].decode('utf-8',errors='replace')
|
||||
tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
|
||||
print(f' entry: {tname} inode={ino} {name!r}')
|
||||
off3 += rec_len
|
||||
Reference in New Issue
Block a user