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})')