#!/usr/bin/env python3 """Independent B21 superblock ordering oracle.""" from __future__ import annotations import argparse import json from pathlib import Path import struct SUPER = 1024 PAGE_SHIFT = 12 FEATURE_COMPAT_SB_CHKSUM = 0x00000001 FEATURE_INCOMPAT_ALL = 0x000001FF FEATURE_INCOMPAT_48BIT = 0x00000080 FEATURE_INCOMPAT_XATTR_PREFIXES = 0x00000040 CRC32C_POLY = 0x82F63B78 def crc32c(data: bytes | bytearray, seed: int = 0xFFFFFFFF) -> int: value = seed for byte in data: value ^= byte for _ in range(8): value = (value >> 1) ^ (CRC32C_POLY if value & 1 else 0) return value & 0xFFFFFFFF def u16(data: bytes, offset: int) -> int: return struct.unpack_from(" int: return struct.unpack_from(" int: return struct.unpack_from(" bool: block_bits = data[SUPER + 12] if not 9 <= block_bits <= PAGE_SHIFT: return False span = 1 << block_bits if span > SUPER: span -= SUPER end = SUPER + span expected = u32(data, SUPER + 4) return expected == crc32c(data[SUPER + 8 : end], 0x5045B54A) def classify(data: bytes) -> tuple[int, str]: if u32(data, SUPER) != 0xE0F5E1E2: return 22, "magic" block_bits = data[SUPER + 12] if not 9 <= block_bits <= PAGE_SHIFT: return 22, "block-size" feature_compat = u32(data, SUPER + 8) if feature_compat & FEATURE_COMPAT_SB_CHKSUM and not checksum_valid(data): return 97, "checksum" if data[SUPER + 90] != 0: return 45, "dirblkbits" feature_incompat = u32(data, SUPER + 80) if feature_incompat & ~FEATURE_INCOMPAT_ALL: if u32(data, SUPER + 92) == 0xFFFFFFFF: return 45, "feature-before-prefix" return 45, "feature-incompat" if 128 + data[SUPER + 13] * 16 > (1 << PAGE_SHIFT) - SUPER: return 22, "super-extension" blocks = u32(data, SUPER + 36) root_nid_8b = u64(data, SUPER + 112) if feature_incompat & FEATURE_INCOMPAT_48BIT and root_nid_8b != 0: blocks |= u16(data, SUPER + 14) << 32 if blocks == 0: return 97, "blocks-zero" if blocks << block_bits > len(data): return 6, "provider-size" if ( feature_incompat & FEATURE_INCOMPAT_XATTR_PREFIXES and data[SUPER + 91] != 0 and u32(data, SUPER + 92) == 0xFFFFFFFF ): return 97, "prefix-offset" return 0, "accepted" def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--fixtures", type=Path, required=True) parser.add_argument("--report", type=Path, required=True) args = parser.parse_args() index = json.loads( (args.fixtures / "fixture-index.json").read_text(encoding="ascii") ) results = [] for item in index["cases"]: path = args.fixtures / item["filename"] actual_errno, actual_reject = classify(path.read_bytes()) passed = ( actual_errno == item["expected_errno"] and actual_reject == item["expected_reject"] ) results.append( { "actual_errno": actual_errno, "actual_reject": actual_reject, "expected_errno": item["expected_errno"], "expected_reject": item["expected_reject"], "id": item["id"], "passed": passed, } ) report = { "batch": "B21", "case_count": len(results), "passed_count": sum(item["passed"] for item in results), "results": results, "schema": 1, "status": "PASS" if all(item["passed"] for item in results) else "FAIL", } args.report.write_text( json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="ascii" ) for item in results: print( f"{'PASS' if item['passed'] else 'FAIL'} {item['id']} " f"errno={item['actual_errno']} reject={item['actual_reject']}" ) return 0 if report["status"] == "PASS" else 1 if __name__ == "__main__": raise SystemExit(main())