Files
ext4recovery/test/find_parent.py
2026-04-30 11:04:05 +00:00

70 lines
2.0 KiB
Python

import subprocess
DEVICE = '/dev/nbd0'
def fls(inode):
try:
r = subprocess.run(['fls', DEVICE, str(inode)],
capture_output=True, text=True, timeout=30)
return r.stdout
except:
return ''
def get_parent_and_name(inode):
output = fls(inode)
parent = None
children = []
for line in output.splitlines():
try:
parts = line.split(None, 2)
if len(parts) < 3: continue
type_str = parts[0]
ino = int(parts[1].rstrip(':').lstrip('*'))
name = parts[2].strip()
if name == '..':
parent = ino
elif name != '.':
children.append((type_str[0], ino, name))
except: continue
return parent, children
# Walk up from pterodactyl
print('Walking up from pterodactyl (inode 1574102)...')
chain = [(1574102, 'pterodactyl')]
inode = 1574102
for _ in range(20):
parent, _ = get_parent_and_name(inode)
if parent is None or parent == inode:
break
grp = (parent-1)//8192
# Get parent's name by looking at its own .. entry
parent_parent, parent_children = get_parent_and_name(parent)
# Find our name in parent's listing
name = f'inode_{parent}'
for t,i,n in parent_children:
if i == inode:
name = n
break
status = 'INTACT' if grp >= 13 else 'LOST'
print(f' [{status}] inode {parent} = {name!r} (group {grp})')
chain.append((parent, name))
if grp < 13:
print(f' Reached zeroed region at inode {parent} - stopping')
break
inode = parent
print()
print('Chain (bottom to top):')
for ino, name in chain:
print(f' {name} (inode {ino})')
# The highest intact inode is our extraction root
top_inode, top_name = chain[-1]
grp = (top_inode-1)//8192
if grp >= 13:
print(f'\nExtraction root: inode {top_inode} ({top_name!r})')
else:
# Use second to last
top_inode, top_name = chain[-2]
print(f'\nExtraction root: inode {top_inode} ({top_name!r})')