82 lines
2.4 KiB
Bash
82 lines
2.4 KiB
Bash
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)')
|
|
"
|