#!/bin/sh
set -eu

: "${PRE15_DUT:?PRE15_DUT is required}"
: "${PRE15_ROOT:?PRE15_ROOT is required}"
: "${PRE15_CASE_TMP:?PRE15_CASE_TMP is required}"
: "${PRE15_RUN_DIR:?PRE15_RUN_DIR is required}"
: "${PRE15_LIB_DIR:?PRE15_LIB_DIR is required}"
. "$PRE15_LIB_DIR/runner.sh"

fixture_dir=$PRE15_DUT/tests/pre15/fixtures
spec=$fixture_dir/B27-stream-tail.json
generator=$fixture_dir/B27-stream-fixtures.py
probe=$fixture_dir/B27-stream-probe.c
compact_probe=$fixture_dir/B27-compact-finalization.c
kld_builder=$fixture_dir/B27-build-kld.sh
gate_script=$PRE15_DUT/tests/pre15/gates/P15-083.sh
gate_input=$PRE15_DUT/tests/pre15/gates/P15-083-input.json
artifacts=$PRE15_RUN_DIR/artifacts
gate_clone=$PRE15_CASE_TMP/gate-clone
gate_output=$PRE15_CASE_TMP/gate-output
first=$PRE15_CASE_TMP/fixtures-first
second=$PRE15_CASE_TMP/fixtures-second

for tool in cc cmp diff dump.erofs fsck.erofs git mkfs.erofs python3 sha256sum timeout; do
	command -v "$tool" >/dev/null 2>&1 || \
		pre15_infra_blocked "missing B27 host tool: $tool"
done

pre15_record_fixture b27-case "$PRE15_DUT/tests/pre15/cases/B27-stream-tail.sh"
pre15_record_fixture b27-spec "$spec"
pre15_record_fixture b27-generator "$generator"
pre15_record_fixture b27-probe "$probe"
pre15_record_fixture b27-compact-finalization "$compact_probe"
pre15_record_fixture b27-kld-builder "$kld_builder"
pre15_record_fixture b27-gate "$gate_script"
pre15_record_fixture b27-gate-input "$gate_input"
for source in decompressor_deflate.c decompressor_lzma.c decompressor_zstd.c \
	    decompressor.c zdata.c zmap.c compress.h; do
	pre15_record_fixture "b27-$source" "$PRE15_DUT/src/$source"
done
mkdir -p "$artifacts"

if ! git clone -q --shared --no-checkout "$PRE15_ROOT" "$gate_clone" \
    >"$artifacts/gate-clone.stdout" 2>"$artifacts/gate-clone.stderr" || \
    ! git -C "$gate_clone" checkout -q --detach \
    338ba8daf81c1461b5d28ca9c5345686e4e0f2eb \
    >"$artifacts/gate-checkout.stdout" 2>"$artifacts/gate-checkout.stderr"; then
	pre15_runner_fail 'could not materialize the frozen P15-083 gate commit'
fi
frozen_gate=$gate_clone/repo-pre-15/tests/pre15/gates/P15-083.sh
if ! (umask 022 && timeout -k 10 240 "$frozen_gate" \
    --base 68bbe94c44e35d53cec8ab55d007f40b01cf0502 \
    --output "$gate_output") >"$artifacts/gate.stdout" \
    2>"$artifacts/gate.stderr"; then
	pre15_runner_fail 'frozen P15-083 gate replay failed'
fi

if ! (umask 022 && python3 -B "$generator" --spec "$spec" --output "$first") \
    >"$artifacts/generate-first.json" 2>"$artifacts/generate-first.stderr"; then
	pre15_runner_fail 'B27 first real EROFS fixture generation failed'
fi
if ! (umask 022 && python3 -B "$generator" --spec "$spec" --output "$second") \
    >"$artifacts/generate-second.json" 2>"$artifacts/generate-second.stderr"; then
	pre15_runner_fail 'B27 second real EROFS fixture generation failed'
fi
if ! diff -qr "$first" "$second" >"$artifacts/fixture-repeat.diff"; then
	pre15_runner_fail 'B27 real EROFS fixtures are not byte reproducible'
fi

cp "$gate_output/result.json" "$artifacts/P15-083-result.json"
cp "$gate_output/codec-results.json" "$artifacts/P15-083-codec-results.json"
cp "$first/fixture-index.json" "$artifacts/B27-fixture-index.json"

if ! cc -std=c11 -Wall -Wextra -Werror "$compact_probe" \
    -o "$PRE15_CASE_TMP/B27-compact-finalization" \
    >"$artifacts/B27-compact-finalization-build.stdout" \
    2>"$artifacts/B27-compact-finalization-build.stderr" || \
    ! "$PRE15_CASE_TMP/B27-compact-finalization" \
    >"$artifacts/B27-compact-finalization.stdout" \
    2>"$artifacts/B27-compact-finalization.stderr"; then
	pre15_dut_fail 'B27 compact HEAD finalization regression failed'
fi
if ! python3 -B - "$PRE15_DUT/src/zmap.c" \
    "$PRE15_DUT/src/decompressor_zstd.c" \
    "$artifacts/B27-compact-finalization-source.json" <<'PY'
import json
from pathlib import Path
import sys

source = Path(sys.argv[1]).read_text(encoding="utf-8")
zstd = Path(sys.argv[2]).read_text(encoding="utf-8")
rejected = """\t\t\t\tif ((lo & Z_EROFS_LI_D0_CBLKCNT) != 0) {
\t\t\t\t\tif (i == 0) {
\t\t\t\t\t\terofs_put_metabuf(&buf);
\t\t\t\t\t\treturn (EINTEGRITY);
\t\t\t\t\t}
"""
accepted = """\t\t\t\tif ((lo & Z_EROFS_LI_D0_CBLKCNT) != 0) {
\t\t\t\t\t--i;
\t\t\t\t\tnblk += lo & ~Z_EROFS_LI_D0_CBLKCNT;
\t\t\t\t\tcontinue;
"""
if rejected in source or source.count(accepted) != 1:
    raise SystemExit("B27 compact HEAD finalization source mismatch")
if zstd.count("\t.supports_subextent = 0,\n") != 1:
    raise SystemExit("B27 Zstd ordinary subextent fallback is disabled")
Path(sys.argv[3]).write_text(json.dumps({
    "cblkcnt_first_slot": "accepted",
    "linux_completion_semantics": True,
    "status": "PASS",
    "zstd_ordinary_subextent": False,
    "zstd_partial_reference_completion": True,
}, indent=2, sort_keys=True) + "\n", encoding="ascii")
PY
then
	pre15_dut_fail 'B27 compact HEAD finalization source audit failed'
fi

if test "${PRE15_QEMU_TARGET_ONLY:-0}" = 1; then
	pre15_target_reached
else
if ! python3 -B - "$PRE15_ROOT" "$PRE15_DUT" "$spec" \
    "$gate_script" "$gate_input" "$gate_output/result.json" \
    "$gate_output/codec-results.json" "$first/fixture-index.json" \
    "$artifacts/B27-source-audit.json" "$PRE15_CASE_TMP/finish-harness.c" <<'PY'
from __future__ import annotations

import hashlib
import json
from pathlib import Path
import re
import subprocess
import sys


root = Path(sys.argv[1])
dut = Path(sys.argv[2])
spec = json.loads(Path(sys.argv[3]).read_text(encoding="ascii"))
gate_script = Path(sys.argv[4])
gate_input = Path(sys.argv[5])
result = json.loads(Path(sys.argv[6]).read_text(encoding="ascii"))
codec_results = json.loads(Path(sys.argv[7]).read_text(encoding="ascii"))
fixture_index = json.loads(Path(sys.argv[8]).read_text(encoding="ascii"))
report_path = Path(sys.argv[9])
harness_path = Path(sys.argv[10])
baseline = spec["baseline"]
implementation = "0eda2fcfc94aba1e51d3f9ee9885260969240de1"
runtime_base = "445da30f913dc292666f340588236498ea793db3"


def fail(message: str) -> None:
    raise SystemExit(message)


def sha256(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


def committed(commit: str, name: str) -> str:
    completed = subprocess.run(
        ["git", "-C", str(root), "show", f"{commit}:repo-pre-15/src/{name}"],
        check=False,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
    )
    if completed.returncode != 0:
        fail(f"cannot read B27 source {commit}:{name}: {completed.stderr.strip()}")
    return completed.stdout


def replace_once(source: str, old: str, new: str, label: str) -> str:
    count = source.count(old)
    if count != 1:
        fail(f"{label}: expected one baseline occurrence, found {count}")
    return source.replace(old, new, 1)


def extract_function(source: str, name: str) -> str:
    match = re.search(r"^" + re.escape(name) + r"\s*\(", source, re.MULTILINE)
    if match is None:
        fail(f"missing function: {name}")
    name_line = source.rfind("\n", 0, match.start()) + 1
    start = source.rfind("\n", 0, name_line - 1) + 1
    brace = source.find("{", match.end())
    depth = 0
    for index in range(brace, len(source)):
        if source[index] == "{":
            depth += 1
        elif source[index] == "}":
            depth -= 1
            if depth == 0:
                return source[start : index + 1]
    fail(f"unterminated function: {name}")


if (
    spec.get("schema") != 1
    or spec.get("batch") != "B27"
    or spec.get("candidate") != "P15-083"
    or spec.get("test") != "TC176-stream-runtime"
):
    fail("B27 fixture identity changed")
if sha256(gate_script) != spec["gate"]["script_sha256"]:
    fail("tracked P15-083 gate script differs from G04 GO")
if sha256(gate_input) != spec["gate"]["input_sha256"]:
    fail("tracked P15-083 gate input differs from G04 GO")
if not (
    result.get("status") == "GO"
    and result.get("b27") == "AUTHORIZED"
    and result.get("cleanup") == "PASS"
    and result.get("typed_errno") == "PASS"
    and result.get("codecs") == {"deflate": "GO", "lzma": "GO", "zstd": "GO"}
):
    fail("frozen P15-083 gate did not reproduce B27 authorization")

observed = {item["codec"]: item for item in codec_results}
if set(observed) != set(spec["codecs"]):
    fail("G04 codec result set changed")
for codec, expected in spec["codecs"].items():
    item = observed[codec]
    gate = expected["gate"]
    extent = expected["extent"]
    if any(item["extent"][key] != extent[key] for key in (
        "leading_zero_bytes", "logical_length", "logical_offset",
        "physical_length", "physical_offset", "stream_bytes"
    )):
        fail(f"{codec} legal leading-padding extent changed")
    checks = (
        item["full"]["consumed"] == gate["full_consumed"],
        item["full"]["policy_errno"] == 0,
        item["partial"]["consumed"] == gate["partial_consumed"],
        item["partial"]["requested_bytes"] == extent["partial_size"],
        item["partial"]["policy_errno"] == 0,
        item["partial"]["corrupt_policy_errno"] == 0,
        item["tail"]["consumed"] == gate["tail_consumed"],
        item["tail"]["policy_errno"] == 97,
        item["tail"]["fsck"]["exit"] == gate["tail_fsck_exit"],
        item["truncated"]["consumed"] == gate["truncated_consumed"],
        item["truncated"]["policy_errno"] == 97,
        item["corruption"]["full_errno"] == 97,
        item["corruption"]["starts_at_stream_byte"] == expected["corruption_start"],
        item["corruption"]["starts_after_partial_consumed"] is True,
    )
    if not all(checks):
        fail(f"{codec} G04 completion/trailing/partial contract changed")
    for phase in ("full", "partial", "tail", "truncated"):
        if item[phase]["cleanup"] != 1 or item[phase]["guards"] != 1:
            fail(f"{codec} {phase} oracle cleanup/guard failed")

if fixture_index.get("fixture_count") != 12 or fixture_index.get("status") != "READY":
    fail("B27 runtime fixture matrix is incomplete")
classes = {(item["codec"], item["class"]) for item in fixture_index["fixtures"]}
if classes != {
    (codec, kind)
    for codec in spec["codecs"]
    for kind in ("valid", "tail", "truncated", "corrupt")
}:
    fail("B27 runtime fixture class set changed")

base = {
    name: committed(baseline, name)
    for name in (
        "compress.h", "decompressor.c", "decompressor_deflate.c",
        "decompressor_lzma.c", "decompressor_zstd.c", "zdata.c"
    )
}
implemented = {name: committed(implementation, name) for name in base}
for name in ("compress.h", "decompressor.c", "zdata.c"):
    if implemented[name] != base[name]:
        fail(f"B27 changed excluded provider/GEOM/buffer-lifetime file: {name}")

deflate_helper = '''static int
z_erofs_deflate_finish(const struct z_erofs_decompress_req *rq, int ret,
    uInt avail_in)
{

\tif (rq->partial_decoding)
\t\treturn (0);
\tif (ret != Z_STREAM_END || avail_in != 0)
\t\treturn (EINTEGRITY);
\treturn (0);
}

'''
expected = replace_once(
    base["decompressor_deflate.c"],
    "static int\nz_erofs_deflate_decompress",
    deflate_helper + "static int\nz_erofs_deflate_decompress",
    "Deflate completion helper",
)
expected = replace_once(
    expected,
    "\telse if (error == 0 && !rq->partial_decoding &&\n"
    "\t    (ret != Z_STREAM_END || strm.avail_in != 0))\n"
    "\t\terror = EINTEGRITY;",
    "\telse if (error == 0)\n"
    "\t\terror = z_erofs_deflate_finish(rq, ret, strm.avail_in);",
    "Deflate completion call",
)
if implemented["decompressor_deflate.c"] != expected:
    fail("Deflate differs from the exact B27 transform")

lzma_helper = '''static int
z_erofs_lzma_finish(const struct z_erofs_decompress_req *rq, enum xz_ret ret,
    size_t input_pos)
{

\tif (rq->partial_decoding &&
\t    (ret == XZ_OK || ret == XZ_STREAM_END))
\t\treturn (0);
\tif (!rq->partial_decoding && ret == XZ_STREAM_END &&
\t    input_pos == rq->inputsize)
\t\treturn (0);
\treturn (z_erofs_lzma_error(ret));
}

'''
expected = replace_once(
    base["decompressor_lzma.c"],
    "static int\nz_erofs_lzma_decompress",
    lzma_helper + "static int\nz_erofs_lzma_decompress",
    "LZMA completion helper",
)
expected = replace_once(
    expected,
    "\telse if (rq->partial_decoding &&\n"
    "\t    (ret == XZ_OK || ret == XZ_STREAM_END))\n"
    "\t\terror = 0;\n"
    "\telse if (!rq->partial_decoding && ret == XZ_STREAM_END &&\n"
    "\t    buffer.in_pos == rq->inputsize)\n"
    "\t\terror = 0;\n"
    "\telse\n"
    "\t\terror = z_erofs_lzma_error(ret);",
    "\telse\n"
    "\t\terror = z_erofs_lzma_finish(rq, ret, buffer.in_pos);",
    "LZMA completion call",
)
if implemented["decompressor_lzma.c"] != expected:
    fail("LZMA differs from the exact B27 transform")

zstd_helper = '''static int
z_erofs_zstd_finish(const struct z_erofs_decompress_req *rq, size_t ret,
    size_t input_pos, size_t input_size)
{

\tif (rq->partial_decoding)
\t\treturn (0);
\tif (ret != 0 || input_pos != input_size)
\t\treturn (EINTEGRITY);
\treturn (0);
}

'''
expected = replace_once(
    base["decompressor_zstd.c"],
    "static const ZSTD_customMem zstd_erofs_alloc = {\n"
    "\t.customAlloc = zstd_alloc,\n"
    "\t.customFree = zstd_free,\n"
    "\t.opaque = M_EROFS,\n"
    "};\n\n"
    "static int\nz_erofs_zstd_decompress",
    "static const ZSTD_customMem zstd_erofs_alloc = {\n"
    "\t.customAlloc = zstd_alloc,\n"
    "\t.customFree = zstd_free,\n"
    "\t.opaque = M_EROFS,\n"
    "};\n\n" + zstd_helper + "static int\nz_erofs_zstd_decompress",
    "Zstd completion helper",
)
expected = replace_once(
    expected,
    "\telse if (error == 0 && !rq->partial_decoding &&\n"
    "\t    (ret != 0 || input.pos != input.size))\n"
    "\t\terror = EINTEGRITY;",
    "\telse if (error == 0)\n"
    "\t\terror = z_erofs_zstd_finish(rq, ret, input.pos, input.size);",
    "Zstd completion call",
)
if implemented["decompressor_zstd.c"] != expected:
    fail("Zstd differs from the exact B27 transform")

runtime_names = (
    "decompressor_deflate.c", "decompressor_lzma.c",
    "decompressor_zstd.c", "zmap.c",
)
runtime_before = {name: committed(runtime_base, name) for name in runtime_names}
current = {
    name: (dut / "src" / name).read_text(encoding="utf-8")
    for name in runtime_names
}
if current["decompressor_deflate.c"] != runtime_before["decompressor_deflate.c"]:
    fail("B27 remediation changed Deflate beyond the accepted implementation")
if current["decompressor_lzma.c"] != runtime_before["decompressor_lzma.c"]:
    fail("B27 remediation changed LZMA beyond the accepted implementation")
if current["decompressor_zstd.c"] != runtime_before["decompressor_zstd.c"]:
    fail("B27 remediation Zstd completion differs from the exact transform")
expected = replace_once(
    runtime_before["zmap.c"],
    "\t\t\t\t\tif (i == 0) {\n"
    "\t\t\t\t\t\terofs_put_metabuf(&buf);\n"
    "\t\t\t\t\t\treturn (EINTEGRITY);\n"
    "\t\t\t\t\t}\n",
    "",
    "compact HEAD first-slot CBLKCNT completion",
)
if current["zmap.c"] != expected:
    fail("B27 remediation compact HEAD completion differs from the exact transform")

changed_source = set(
    subprocess.run(
        ["git", "-C", str(root), "diff", "--name-only", runtime_base, "--", "repo-pre-15/src"],
        check=True,
        text=True,
        stdout=subprocess.PIPE,
    ).stdout.splitlines()
)
if changed_source != {
    "repo-pre-15/src/zmap.c",
}:
    fail(f"B27 source write set changed: {sorted(changed_source)}")

all_changed = set(
    subprocess.run(
        ["git", "-C", str(root), "diff", "--name-only", runtime_base, "--", "repo-pre-15"],
        check=True,
        text=True,
        stdout=subprocess.PIPE,
    ).stdout.splitlines()
)
all_changed.update(
    subprocess.run(
        ["git", "-C", str(root), "ls-files", "--others", "--exclude-standard", "--", "repo-pre-15"],
        check=True,
        text=True,
        stdout=subprocess.PIPE,
    ).stdout.splitlines()
)
expected_write_set = {
    "repo-pre-15/src/zmap.c",
    "repo-pre-15/tests/pre15/cases/B27-stream-tail.sh",
    "repo-pre-15/tests/pre15/fixtures/B27-compact-finalization.c",
}
if all_changed != expected_write_set:
    fail(f"B27 exact write set differs: {sorted(all_changed ^ expected_write_set)}")

joined = "\n".join(current.values())
if re.search(r"return\s*\(\s*-E[A-Z0-9_]+", joined):
    fail("negative Linux errno entered B27")
if "ZSTD_getErrorCode" in current["decompressor_zstd.c"]:
    fail("B27 expanded the optional Zstd provider ABI")

linux = {
    codec: (root / f"src-linux/decompressor_{codec}.c").read_text(encoding="utf-8")
    for codec in spec["codecs"]
}
for codec, marker in {
    "deflate": "if (zerr == Z_STREAM_END && !rq->outputsize)",
    "lzma": "xz_dec_microlzma_reset(strm->state, rq->inputsize, rq->outputsize",
    "zstd": "zerr = zstd_decompress_stream(stream, &out_buf, &in_buf);",
}.items():
    if marker not in linux[codec]:
        fail(f"Linux {codec} stream-tail anchor changed")

harness = f'''#include <stddef.h>
#include <stdio.h>

#define EINTEGRITY 97
#define ENOMEM 12
#define EOPNOTSUPP 95
#define Z_STREAM_END 1
typedef unsigned int uInt;

enum xz_ret {{
    XZ_OK, XZ_STREAM_END, XZ_UNSUPPORTED_CHECK, XZ_MEM_ERROR,
    XZ_MEMLIMIT_ERROR, XZ_FORMAT_ERROR, XZ_OPTIONS_ERROR,
    XZ_DATA_ERROR, XZ_BUF_ERROR
}};

struct z_erofs_decompress_req {{
    int partial_decoding;
    size_t inputsize;
}};

{extract_function(current["decompressor_lzma.c"], "z_erofs_lzma_error")}

{extract_function(current["decompressor_deflate.c"], "z_erofs_deflate_finish")}

{extract_function(current["decompressor_lzma.c"], "z_erofs_lzma_finish")}

{extract_function(current["decompressor_zstd.c"], "z_erofs_zstd_finish")}

static int failures;

static void
check(const char *name, int actual, int expected)
{{
    if (actual != expected) {{
        fprintf(stderr, "%s: actual=%d expected=%d\\n", name, actual, expected);
        failures++;
    }}
}}

int
main(void)
{{
    struct z_erofs_decompress_req full = {{ 0, 548 }};
    struct z_erofs_decompress_req partial = {{ 1, 548 }};

    check("deflate exact", z_erofs_deflate_finish(&full, Z_STREAM_END, 0), 0);
    check("deflate tail", z_erofs_deflate_finish(&full, Z_STREAM_END, 8), EINTEGRITY);
    check("deflate no end", z_erofs_deflate_finish(&full, 0, 0), EINTEGRITY);
    check("deflate partial", z_erofs_deflate_finish(&partial, 0, 8), 0);
    check("lzma exact", z_erofs_lzma_finish(&full, XZ_STREAM_END, 548), 0);
    check("lzma tail", z_erofs_lzma_finish(&full, XZ_STREAM_END, 540), EINTEGRITY);
    check("lzma no end", z_erofs_lzma_finish(&full, XZ_OK, 548), EINTEGRITY);
    check("lzma partial", z_erofs_lzma_finish(&partial, XZ_OK, 352), 0);
    check("lzma partial error", z_erofs_lzma_finish(&partial, XZ_DATA_ERROR, 352), EINTEGRITY);
    check("zstd exact", z_erofs_zstd_finish(&full, 0, 548, 548), 0);
    check("zstd tail", z_erofs_zstd_finish(&full, 0, 540, 548), EINTEGRITY);
    check("zstd no end", z_erofs_zstd_finish(&full, 1, 548, 548), EINTEGRITY);
    check("zstd partial", z_erofs_zstd_finish(&partial, 1, 352, 548), 0);
    return failures != 0;
}}
'''
harness_path.write_text(harness, encoding="ascii")

report = {
    "baseline": baseline,
    "batch": "B27",
    "candidate": "P15-083",
    "cleanup_and_guards": True,
    "codecs": sorted(spec["codecs"]),
    "fixture_count": fixture_index["fixture_count"],
    "freebsd_positive_errno": True,
    "gate": "GO",
    "legal_leading_padding_preserved": True,
    "linux_tail_semantics_audited": True,
    "optional_zstd_abi_preserved": True,
    "provider_geom_and_buffer_lifetime_unchanged": True,
    "runtime_base": runtime_base,
    "status": "PASS",
    "test": "TC176-stream-runtime",
    "write_set": sorted(all_changed),
}
report_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="ascii")
print(json.dumps(report, indent=2, sort_keys=True))
PY
then
	pre15_runner_fail 'B27 gate/source/write-set audit failed'
fi

if ! cc -std=c11 -Wall -Wextra -Werror "$PRE15_CASE_TMP/finish-harness.c" \
    -o "$PRE15_CASE_TMP/finish-harness" >"$artifacts/finish-harness-build.stdout" \
    2>"$artifacts/finish-harness-build.stderr" || \
    ! "$PRE15_CASE_TMP/finish-harness" >"$artifacts/finish-harness.stdout" \
    2>"$artifacts/finish-harness.stderr"; then
	pre15_dut_fail 'B27 extracted completion policy harness failed'
fi
sha256sum "$artifacts/P15-083-result.json" \
    "$artifacts/P15-083-codec-results.json" \
    "$artifacts/B27-fixture-index.json" \
    "$artifacts/B27-source-audit.json" >"$artifacts/SHA256SUMS"
fi
pre15_target_reached

if test "${PRE15_MODE:-host}" != qemu; then
	printf '%s\n' \
		'TC176 B27 host real LZMA/Deflate/Zstd stream-tail subset PASS' \
		'Legal padding, trailing garbage, truncation, partial decode, corruption, positive errno, and cleanup PASS' \
		'QEMU runtime NOT_RUN in host mode' \
		'Full feature suite NOT_RUN'
	exit 0
fi

for tool in awk clang file nm scp tar; do
	command -v "$tool" >/dev/null 2>&1 || \
		pre15_infra_blocked "missing B27 QEMU tool: $tool"
done
: "${PRE15_QEMU_CONTROL_PATH:?QEMU control path is required}"
: "${PRE15_QEMU_SSH_KEY:?QEMU SSH key is required}"
: "${PRE15_QEMU_SSH_PORT:?QEMU SSH port is required}"
: "${PRE15_QEMU_SSH_USER:?QEMU SSH user is required}"

fixture_archive=$PRE15_CASE_TMP/B27-fixtures.tar.gz
module=$PRE15_CASE_TMP/B27-erofs-zstdio1.ko
if ! /bin/sh "$kld_builder" "$PRE15_DUT" "$PRE15_FREEBSD_SRC" "$module" \
    "$PRE15_CASE_TMP/kld-work" 1 >"$artifacts/B27-kld-build.stdout" \
    2>"$artifacts/B27-kld-build.stderr"; then
	pre15_dut_fail 'B27 cross-target zstdio1 KLD build failed'
fi
pre15_record_module "$module"
file "$module" >"$artifacts/B27-kld-file.txt"
sha256sum "$module" >"$artifacts/B27-kld-sha256.txt"
nm -u "$module" | LC_ALL=C sort >"$artifacts/B27-kld-nm-u.txt"
tar -C "$first" -czf "$fixture_archive" .

pre15_scp()
{
	timeout -k 5 "${PRE15_GUEST_COMMAND_TIMEOUT:-60}" scp -O -q \
		-o BatchMode=yes -o StrictHostKeyChecking=no \
		-o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 \
		-o "ControlPath=$PRE15_QEMU_CONTROL_PATH" \
		-i "$PRE15_QEMU_SSH_KEY" -P "$PRE15_QEMU_SSH_PORT" \
		"$1" "$PRE15_QEMU_SSH_USER@127.0.0.1:$2"
}

if ! pre15_scp "$fixture_archive" /root/B27-fixtures.tar.gz || \
    ! pre15_scp "$probe" /root/B27-stream-probe.c || \
    ! pre15_scp "$module" /root/B27-erofs-zstdio1.ko; then
	pre15_infra_blocked 'could not transfer B27 module, probe, or fixtures'
fi
if ! pre15_guest_ssh_bounded \
    'rm -rf /root/B27-fixtures && mkdir /root/B27-fixtures && tar -xzf /root/B27-fixtures.tar.gz -C /root/B27-fixtures && cc -O2 -Wall -Wextra -Werror -o /root/B27-stream-probe /root/B27-stream-probe.c'; then
	pre15_infra_blocked 'could not prepare B27 guest fixtures/probe'
fi
if pre15_guest_ssh_bounded kldstat -q -m erofs >/dev/null 2>&1; then
	pre15_infra_blocked 'guest kernel already owns the erofs.1 interface'
fi
if ! pre15_guest_ssh_bounded kldload /root/B27-erofs-zstdio1.ko \
    >"$artifacts/B27-kldload.stdout" 2>"$artifacts/B27-kldload.stderr"; then
	if grep -q 'module already loaded or in kernel' \
	    "$artifacts/B27-kldload.stderr"; then
		pre15_infra_blocked 'guest kernel already owns the erofs.1 interface'
	fi
	if grep -Eq 'link_elf|symbol|not defined' "$artifacts/B27-kldload.stderr"; then
		pre15_infra_blocked 'guest kernel lacks the planned ZSTDIO provider ABI'
	fi
	pre15_dut_fail 'B27 exact-source zstdio1 KLD failed to load'
fi
pre15_own_guest_kld erofs 'B27 exact-source KLD'

attach_mount()
{
	image=$1
	label=$2
	B27_MD=$(pre15_guest_ssh_bounded mdconfig -a -t vnode \
		-f "/root/B27-fixtures/images/$image") || \
		pre15_dut_fail "$label md attach failed"
	case "$B27_MD" in
	md[0-9]*) ;;
	*) pre15_runner_fail "unexpected B27 md unit: $B27_MD" ;;
	esac
	pre15_own_guest_md "$B27_MD" "$label md"
	B27_MOUNT=/mnt/pre15-b27-$label
	pre15_guest_ssh_bounded mkdir -p "$B27_MOUNT"
	pre15_guest_ssh_bounded mount -t erofs -o ro "/dev/$B27_MD" "$B27_MOUNT" || \
		pre15_dut_fail "$label mount failed"
	pre15_own_guest_mount "$B27_MOUNT" "$label mount"
}

reference=/root/B27-fixtures/source/payload.bin
for codec in deflate lzma zstd; do
	attach_mount "$codec-valid.erofs" "$codec-valid"
	pre15_guest_ssh_bounded cmp "$B27_MOUNT/payload.bin" "$reference" || \
		pre15_dut_fail "$codec legal leading-padding read mismatch"
	for kind in tail truncated; do
		attach_mount "$codec-$kind.erofs" "$codec-$kind"
		pre15_guest_ssh_bounded /root/B27-stream-probe errno \
		    "$B27_MOUNT/payload.bin" 97 || \
			pre15_dut_fail "$codec $kind did not return EINTEGRITY"
	done
	case "$codec" in
	deflate) logical_offset=137204; partial_size=3587 ;;
	lzma|zstd) logical_offset=0; partial_size=4096 ;;
	esac
	attach_mount "$codec-corrupt.erofs" "$codec-corrupt"
	pre15_guest_ssh_bounded /root/B27-stream-probe range \
	    "$B27_MOUNT/payload.bin" "$reference" "$logical_offset" \
	    "$partial_size" || \
		pre15_dut_fail "$codec range-before-corruption partial decode failed"
	pre15_guest_ssh_bounded /root/B27-stream-probe errno \
	    "$B27_MOUNT/payload.bin" 97 || \
		pre15_dut_fail "$codec full corruption did not return EINTEGRITY"
done
pre15_guest_ssh_bounded dmesg >"$artifacts/B27-dmesg.txt"
printf '%s\n' \
	'TC176 B27 QEMU real LZMA/Deflate/Zstd stream-tail subset PASS' \
	'valid=3 trailing=3 truncated=3 partial-before-corruption=3 full-corruption=3 errno=97' \
	'Full feature suite NOT_RUN'
