python3 -c "
import struct
import binascii

CHUNK = 128*512
LV_START = 5120000*512
BSIZE = 4096
GDT_ENTRY = 64
BPG = 32768
NUM_GROUPS = 35728

def raw_read(virt_offset, length):
    result = bytearray(length)
    pos = virt_offset
    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_offset
            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)

# Read UUID and checksum seed from superblock
sb = raw_read(1024, 1024)
uuid = sb[104:120]
csum_seed = struct.unpack_from('<I', sb, 408)[0]
print(f'UUID: {uuid.hex()}')
print(f'csum_seed: 0x{csum_seed:08x}')

# Read backup GDT
backup_gdt = bytearray(raw_read((BPG+1)*BSIZE, NUM_GROUPS * GDT_ENTRY))

# CRC32c implementation
try:
    import crcmod
    crc32c_fn = crcmod.predefined.mkCrcFun('crc-32c')
    def crc32c(data, seed=0):
        return crc32c_fn(data, seed)
except ImportError:
    # Fallback: use kernel-compatible crc32c via ctypes
    import ctypes
    try:
        lib = ctypes.CDLL('libiscsi.so.2')
        def crc32c(data, seed=0):
            return lib.iscsi_crc32c(data, len(data), seed)
    except:
        print('WARNING: no crc32c available, checksums will be wrong')
        def crc32c(data, seed=0):
            return 0

# Recalculate and patch checksums for all GDT entries
print(f'Patching checksums for {NUM_GROUPS} groups...')
bad = 0
for g in range(NUM_GROUPS):
    entry = bytearray(backup_gdt[g*GDT_ENTRY:(g+1)*GDT_ENTRY])
    
    # Zero out checksum field (offset 30, 2 bytes) before computing
    struct.pack_into('<H', entry, 30, 0)
    
    # CRC32c(seed XOR uuid XOR group_le16 XOR entry_without_csum)
    grp_le = struct.pack('<H', g)
    csum_data = uuid + grp_le + bytes(entry)
    csum = crc32c(csum_data, csum_seed) & 0xFFFF
    
    struct.pack_into('<H', entry, 30, csum)
    backup_gdt[g*GDT_ENTRY:(g+1)*GDT_ENTRY] = entry

with open('/tmp/patched_gdt.bin','wb') as f:
    f.write(backup_gdt)
print(f'Written /tmp/patched_gdt.bin ({len(backup_gdt)//1024}KB)')
"
