import struct

BSIZE = 4096
IPG   = 8192

def read_block(f, block_num):
    f.seek(block_num * BSIZE)
    return f.read(BSIZE)

def get_extents(inode_data):
    blocks = []
    if struct.unpack_from('<H', inode_data, 40)[0] != 0xf30a:
        return blocks
    entries = struct.unpack_from('<H', inode_data, 42)[0]
    depth   = struct.unpack_from('<H', inode_data, 46)[0]
    if depth == 0:
        for i in range(min(entries, 4)):
            off    = 52 + i*12
            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]
            start  = (ee_hi<<32)|ee_lo
            for b in range(min(ee_len, 8)):
                blocks.append(start + b)
    return blocks

def read_inode(f, inode_num):
    group    = (inode_num-1)//IPG
    idx      = (inode_num-1)%IPG
    it_block = 1070 + group*512
    f.seek(it_block*BSIZE + idx*256)
    return f.read(256)

def list_dir(f, inode_num):
    data = read_inode(f, inode_num)
    entries = []
    for blk in get_extents(data):
        blk_data = read_block(f, blk)
        off = 0
        while off < BSIZE - 8:
            ino     = struct.unpack_from('<I', blk_data, off)[0]
            rec_len = struct.unpack_from('<H', blk_data, off+4)[0]
            name_len= blk_data[off+6]
            ftype   = blk_data[off+7]
            if rec_len < 8: break
            if ino > 0 and name_len > 0:
                name = blk_data[off+8:off+8+name_len].decode('utf-8',errors='replace')
                if name not in ('.','..'):
                    entries.append((ino, name, ftype))
            off += rec_len
    return entries

with open('/dev/nbd0','rb') as f:
    # /var = inode 1310721
    print('=== /var (inode 1310721) ===')
    for ino, name, ftype in list_dir(f, 1310721):
        tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
        print(f'  {tname:4s} {name:30s} inode={ino}')

    # Find /var/lib
    print()
    for ino, name, ftype in list_dir(f, 1310721):
        if name == 'lib':
            print(f'=== /var/lib (inode {ino}) ===')
            for i2, n2, f2 in list_dir(f, ino):
                tname = {1:'file',2:'dir',7:'link'}.get(f2,'?')
                print(f'  {tname:4s} {n2:30s} inode={i2}')

            # Find pterodactyl
            for i2, n2, f2 in list_dir(f, ino):
                if n2 == 'pterodactyl':
                    print(f'\n=== /var/lib/pterodactyl (inode {i2}) ===')
                    for i3, n3, f3 in list_dir(f, i2):
                        tname = {1:'file',2:'dir',7:'link'}.get(f3,'?')
                        print(f'  {tname:4s} {n3:30s} inode={i3}')
