import struct

with open('/tmp/fs_meta.img', 'r+b') as f:
    f.seek(1024)
    sb = bytearray(f.read(1024))
    
    ro_compat = struct.unpack_from('<I', sb, 100)[0]
    incompat  = struct.unpack_from('<I', sb,  96)[0]
    compat    = struct.unpack_from('<I', sb,  92)[0]
    
    print(f'Before: compat=0x{compat:08x} incompat=0x{incompat:08x} ro_compat=0x{ro_compat:08x}')
    
    incompat  &= ~0x004   # clear HAS_JOURNAL
    ro_compat &= ~0x400   # clear METADATA_CSUM
    ro_compat &= ~0x010   # clear GDT_CSUM
    compat    &= ~0x004   # clear HAS_JOURNAL from compat too
    
    # Zero the journal inode number so e2fsck ignores it
    struct.pack_into('<I', sb, 180, 0)  # s_journal_inum = 0
    
    struct.pack_into('<I', sb,  92, compat)
    struct.pack_into('<I', sb,  96, incompat)
    struct.pack_into('<I', sb, 100, ro_compat)
    struct.pack_into('<I', sb, 1020, 0)  # clear sb checksum
    
    f.seek(1024)
    f.write(bytes(sb))
    print(f'After:  compat=0x{compat:08x} incompat=0x{incompat:08x} ro_compat=0x{ro_compat:08x}')

# Zero all GDT checksums
with open('/tmp/fs_meta.img', 'r+b') as f:
    f.seek(4096)
    gdt = bytearray(f.read(35728 * 64))
    for g in range(35728):
        struct.pack_into('<H', gdt, g*64+30, 0)
    f.seek(4096)
    f.write(bytes(gdt))
    print('GDT checksums zeroed')
