import struct

CHUNK    = 128*512
LV_START = 5120000*512
BSIZE    = 4096
BPG      = 32768

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)

# Load GDT
NUM_GROUPS = 35728
gdt_data = read_virt(BSIZE, NUM_GROUPS*64)

def get_block_bitmap_block(group):
    entry = gdt_data[group*64:(group+1)*64]
    bb_lo = struct.unpack_from('<I', entry,  0)[0]
    bb_hi = struct.unpack_from('<I', entry, 32)[0]
    return (bb_hi<<32)|bb_lo

def is_block_allocated(block_num):
    group  = block_num // BPG
    offset = block_num % BPG
    bb_block = get_block_bitmap_block(group)
    bitmap = read_virt(bb_block*BSIZE, BSIZE)
    byte_idx = offset // 8
    bit_idx  = offset % 8
    return bool(bitmap[byte_idx] & (1 << bit_idx))

for block, name in [(6300141,'volumes'), (6299897,'pterodactyl'), (5251104,'var')]:
    allocated = is_block_allocated(block)
    virt = block * BSIZE
    in_group  = virt % (5*CHUNK)
    chunk_idx = in_group // CHUNK
    print(f'{name:15s} block={block:8d} chunk_idx={chunk_idx} '
          f'allocated={allocated}')
