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