#!/bin/sh set -eu : "${PRE15_DUT:?PRE15_DUT is required}" : "${PRE15_ROOT:?PRE15_ROOT is required}" : "${PRE15_RUN_DIR:?PRE15_RUN_DIR is required}" : "${PRE15_LIB_DIR:?PRE15_LIB_DIR is required}" . "$PRE15_LIB_DIR/runner.sh" gate=$PRE15_DUT/tests/pre15/gates/P15-006.sh input=$PRE15_DUT/tests/pre15/gates/P15-006-input.json oracle=$PRE15_DUT/tests/pre15/fixtures/B07-map-oracle.json artifacts=$PRE15_RUN_DIR/artifacts for tool in cc python3 sha256sum; do command -v "$tool" >/dev/null 2>&1 || \ pre15_infra_blocked "missing B07a host tool: $tool" done pre15_record_fixture b07a-gate "$gate" pre15_record_fixture b07a-input "$input" pre15_record_fixture b07a-oracle "$oracle" for source in internal.h data.c zmap.c zdata.c super.c; do pre15_record_fixture "b07a-$source" "$PRE15_DUT/src/$source" done mkdir -p "$artifacts" pre15_target_reached if "$gate" --worktree --oracle "$oracle" --output "$artifacts/gate" \ >"$artifacts/gate.stdout" 2>"$artifacts/gate.stderr"; then : else pre15_dut_fail 'B07a P15-006 candidate replay failed' fi if python3 - "$PRE15_DUT" "$oracle" "$artifacts/gate" \ "$artifacts/adapter-check.json" <<'PY' from __future__ import annotations import json from pathlib import Path import re import sys dut = Path(sys.argv[1]) oracle = json.loads(Path(sys.argv[2]).read_text(encoding="ascii")) gate = Path(sys.argv[3]) output = Path(sys.argv[4]) result = json.loads((gate / "result.json").read_text(encoding="ascii")) tuples = json.loads((gate / "tuples.json").read_text(encoding="ascii")) devices = json.loads((gate / "devices.json").read_text(encoding="ascii")) if result["status"] != "GO" or result["failures"]: raise SystemExit(f"P15-006 candidate did not GO: {result!r}") if not result["adapter_mode"] or result["oracle_equal"] is not True: raise SystemExit("candidate did not use the common map adapter and frozen oracle") if result["map_case_count"] != 80 or result["device_case_count"] != 13: raise SystemExit("P15-006 corpus denominator changed") if result["model_sha256"] != oracle["model_sha256"]: raise SystemExit("independent model digest changed") if result["tuple_bytes_sha256"] != oracle["tuple_bytes_sha256"]: raise SystemExit("tuple byte stream changed") if result["adapter_probe"]["status"] != "PASS": raise SystemExit("FULL/COMPACT adapter pass-through probe failed") if not result["adapter_probe"]["full_and_compact_dispatch"]: raise SystemExit("compressed layout dispatch is incomplete") if result["adapter_probe"]["flag_mask"] != 0x1F: raise SystemExit("not all map flag bits passed through the adapter") if tuples["tuple_bytes_sha256"] != oracle["tuple_bytes_sha256"]: raise SystemExit("tuple artifact does not match frozen bytes") if devices["status"] != "PASS" or len(devices["records"]) != 13: raise SystemExit("device/GEOM resolution oracle failed") def extract_function(source: str, name: str) -> str: match = re.search(r"^" + re.escape(name) + r"\s*\(", source, re.MULTILINE) if not match: raise SystemExit(f"missing function: {name}") start = source.rfind("\n\n", 0, match.start()) + 2 brace = source.find("{", match.end()) depth = 0 state = "code" index = brace while index < len(source): char = source[index] following = source[index + 1] if index + 1 < len(source) else "" if state == "code": if char == "/" and following == "*": state = "block" index += 2 continue if char == "/" and following == "/": state = "line" index += 2 continue if char == '"': state = "string" elif char == "'": state = "character" elif char == "{": depth += 1 elif char == "}": depth -= 1 if depth == 0: return source[start : index + 1] elif state == "block" and char == "*" and following == "/": state = "code" index += 2 continue elif state == "line" and char == "\n": state = "code" elif state in {"string", "character"}: if char == "\\": index += 2 continue if (state == "string" and char == '"') or ( state == "character" and char == "'" ): state = "code" index += 1 raise SystemExit(f"unterminated function: {name}") internal = (dut / "src/internal.h").read_text(encoding="utf-8") data = (dut / "src/data.c").read_text(encoding="utf-8") zmap = (dut / "src/zmap.c").read_text(encoding="utf-8") zdata = (dut / "src/zdata.c").read_text(encoding="utf-8") super_source = (dut / "src/super.c").read_text(encoding="utf-8") object_prototype = re.search( r"int erofs_map_blocks\s*\(struct erofs_sb_info \*sbi,\s*" r"struct erofs_inode \*vi,\s*struct erofs_map_blocks \*map\s*\);", internal, re.MULTILINE, ) if object_prototype is None: raise SystemExit("common map object prototype is absent") if re.search(r"erofs_map_blocks\s*\([^;]*phys_off", internal, re.DOTALL): raise SystemExit("legacy scatter prototype remains exported") if "static int\nerofs_map_blocks_legacy(" not in data: raise SystemExit("legacy producer target is not file-local") if len(re.findall(r"\berofs_map_blocks_legacy\s*\(", data)) != 4: raise SystemExit("B07a must retain exactly two legacy data consumers") if len(re.findall(r"\berofs_map_blocks\s*\(", data)) != 1: raise SystemExit("B07a common map entry has an unexpected data.c caller") adapter = extract_function(data, "erofs_map_blocks") required_adapter = [ "struct erofs_map_blocks next = { .m_la = map->m_la };", "z_erofs_map_blocks_iter(sbi, vi, &next, 0);", "next.m_deviceid = device_id;", "next.m_flags |= EROFS_MAP_MAPPED;", "next.m_flags |= EROFS_MAP_META;", "*map = next;", ] for marker in required_adapter: if marker not in adapter: raise SystemExit(f"adapter contract marker is absent: {marker}") for function in ("erofs_read_data", "erofs_read_uio"): body = extract_function(data, function) if "erofs_map_blocks_legacy(" not in body or "erofs_map_blocks(" in body: raise SystemExit(f"B07a migrated consumer early: {function}") for source_name, source in (("zdata.c", zdata), ("super.c", super_source)): if "z_erofs_map_blocks_iter(" not in source or "erofs_map_blocks(" in source: raise SystemExit(f"B07a migrated compressed consumer early: {source_name}") if "map adapter must preserve every map flag" not in zmap: raise SystemExit("compressed map flag contract assertion is absent") summary = { "status": "PASS", "map_cases": result["map_case_count"], "device_cases": result["device_case_count"], "tuple_bytes_sha256": result["tuple_bytes_sha256"], "model_sha256": result["model_sha256"], "adapter_probe": result["adapter_probe"], "legacy_data_consumers": 2, "compressed_consumers_migrated": False, "qemu": result["qemu"], "full_feature_suite": result["full_feature_suite"], } with output.open("x", encoding="ascii") as stream: json.dump(summary, stream, ensure_ascii=True, indent=2, sort_keys=True) stream.write("\n") print("B07a PASS map=80 device=13 tuple-bytes exact flags=0x1f") PY then : else pre15_dut_fail 'B07a adapter boundary check failed' fi sha256sum "$artifacts/gate/result.json" "$artifacts/gate/tuples.json" \ "$artifacts/gate/devices.json" "$artifacts/adapter-check.json" \ >"$artifacts/SHA256SUMS" printf 'B07a PASS exact map adapter; producers and consumers remain staged\n'