# Inode 2 is at virtual byte 4382976 via NBD
# Group 0 inode table should be at block = 4382976 // 4096 = 1069 or 1070?
virt = 4382976
BSIZE = 4096
block = virt // BSIZE
offset_in_block = virt % BSIZE
inode_idx = offset_in_block // 256

print(f'Inode 2 virtual byte: {virt}')
print(f'Block: {block}')
print(f'Offset in block: {offset_in_block}')
print(f'Inode index in block: {inode_idx}')

# istat said direct block = 9262 for root dir data
# That means the root directory data is at block 9262
# Let's read that directly via NBD
import struct

BSIZE = 4096
with open('/dev/nbd0','rb') as f:
    f.seek(9262 * BSIZE)
    data = f.read(BSIZE)

print()
print('Root directory data block (block 9262):')
off = 0
while off < BSIZE - 8:
    ino     = struct.unpack_from('<I', data, off)[0]
    rec_len = struct.unpack_from('<H', data, off+4)[0]
    name_len= data[off+6]
    ftype   = data[off+7]
    if rec_len < 8: break
    if ino > 0 and name_len > 0:
        name = data[off+8:off+8+name_len].decode('utf-8',errors='replace')
        tname = {1:'file',2:'dir',7:'link'}.get(ftype,'?')
        print(f'  {tname:4s} inode={ino:10d} {name!r}')
    off += rec_len

# Now check: our formula says group 0 inode table is at block 1070
# But inode 2 is at virtual byte 4382976 = block 1069.something?
print()
print(f'Our formula block: 1070')
print(f'Actual block from NBD: {virt//BSIZE} (byte {virt})')
print(f'Difference: {1070 - virt//BSIZE}')

# The key question: is our GDT formula wrong?
# GDT says inode table at block 1070 for group 0
# But inode 2 (second inode) is at:
# block 1070, offset 256 bytes (one inode size)
# = byte 1070*4096 + 256 = 4382976 + 256... wait
print()
print(f'1070 * 4096 = {1070*4096}')
print(f'1070 * 4096 + 256 = {1070*4096+256}')
print(f'Actual inode 2 virt byte from NBD: {virt}')
print(f'Match: {1070*4096+256 == virt}')
