CHUNK = 128*512 LV_START = 5120000*512 BSIZE = 4096 # We know block 9262 is the root directory data block # and it reads correctly. Let's find its chunk position. known_virt = 9262 * BSIZE group = known_virt // (5*CHUNK) in_group = known_virt % (5*CHUNK) chunk_idx = in_group // CHUNK intra = in_group % CHUNK print(f'Root dir block 9262: chunk_group={group} chunk_idx={chunk_idx}') # Now check the 5th chunk in the SAME group meta_virt = group * 5 * CHUNK + 4 * CHUNK print(f'5th chunk in same group at phys byte: {LV_START + meta_virt}') # Read 512 bytes from the 5th chunk with open('/dev/md0','rb') as f: f.seek(LV_START + meta_virt) data = f.read(512) print(f'First 64 bytes: {data[:64].hex()}') print() # Compare with what we read from the PERC metadata chunk earlier # istat showed volumes dir data at block 5251104 (chunk_idx=4) # Let's check if that block's data might actually be at a different # physical location - maybe the PERC remapped it # What if for chunk_idx=4, the data is stored in a DIFFERENT disk's # corresponding chunk? i.e. the PERC uses the 5th physical chunk # on a different disk? # Our disk order: sda(0) sde(1) sdd(2) sdc(3) # In RAID0: chunk N goes to disk N%4 # For a group of 5 virtual chunks: # virtual chunk 0 -> disk 0 # virtual chunk 1 -> disk 1 # virtual chunk 2 -> disk 2 # virtual chunk 3 -> disk 3 # virtual chunk 4 -> ??? (metadata chunk - no disk?) # BUT: if the physical layout has 5 chunks per group across 4 disks # maybe it's: disk0 gets chunks 0,4 / disk1 gets chunk1 / etc? # Or maybe all 5 chunks exist on disk but chunk 4 is PERC metadata # that happens to occupy the same space as filesystem data? # The PERC sector-level metadata we found earlier: # Each 64KB metadata chunk stores 512 bytes per sector of the adjacent data # That's 128 sectors * 512 bytes = 64KB of per-sector checksums/metadata # So the 5th chunk IS pure PERC internal data, not filesystem data # This means: filesystem block 5251104 maps to virtual chunk_idx=4 # BUT the actual filesystem data for that block must be stored differently # OR the block number in the inode is a VIRTUAL block number # that the PERC translates differently than we think # Let's check: what if block numbers in inodes are PERC virtual block numbers? # PERC virtual block 5251104: # In PERC virtual space (5 chunks per group): # group = 5251104*4096 // (5*CHUNK) = ? perc_virt_byte = 5251104 * BSIZE perc_group = perc_virt_byte // (5*CHUNK) perc_in_group = perc_virt_byte % (5*CHUNK) perc_chunk_idx = perc_in_group // CHUNK perc_intra = perc_in_group % CHUNK print(f'If block 5251104 is PERC virtual:') print(f' PERC group={perc_group} chunk_idx={perc_chunk_idx} intra={perc_intra}') # And the physical location would be: # physical = LV_START + perc_group*4*CHUNK + perc_chunk_idx*CHUNK + perc_intra if perc_chunk_idx != 4: phys = LV_START + perc_group*4*CHUNK + perc_chunk_idx*CHUNK + perc_intra print(f' Physical byte: {phys}') with open('/dev/md0','rb') as f: f.seek(phys) data = f.read(BSIZE) nonzero = sum(1 for b in data if b != 0) print(f' Nonzero: {nonzero}/4096') print(f' First 32: {data[:32].hex()}') # Try to parse as directory import struct off = 0 print(' Directory entries:') 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} inode={ino} {name!r}') off += rec_len else: print(f' Still in metadata chunk!')