This commit is contained in:
2026-08-18 09:20:44 +02:00
commit b826cd721a
522 changed files with 93730 additions and 0 deletions
+275
View File
@@ -0,0 +1,275 @@
#!/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"
fixtures_only=0
if test "${1:-}" = --fixtures-only; then
fixtures_only=1
shift
fi
test "$#" -eq 0 || pre15_runner_fail 'B17 accepts only --fixtures-only'
fixture_dir=$PRE15_DUT/tests/pre15/fixtures
spec=$fixture_dir/B17-xattr-spec.json
generator=$fixture_dir/B17-xattr-generate.py
oracle=$fixture_dir/B17-xattr-oracle.py
seed=$fixture_dir/B17-xattr-seed.erofs
artifacts=$PRE15_RUN_DIR/artifacts
first=$PRE15_CASE_TMP/first
second=$PRE15_CASE_TMP/second
rebuilt=$PRE15_CASE_TMP/rebuilt-seed.erofs
rebuild_work=$PRE15_CASE_TMP/rebuild-work
for tool in fsck.erofs git mkfs.erofs python3 sha256sum; do
command -v "$tool" >/dev/null 2>&1 || \
pre15_infra_blocked "missing B17 host tool: $tool"
done
pre15_record_fixture b17-spec "$spec"
pre15_record_fixture b17-generator "$generator"
pre15_record_fixture b17-oracle "$oracle"
pre15_record_fixture b17-seed "$seed"
pre15_record_fixture b17-case "$PRE15_DUT/tests/pre15/cases/B17-xattr-integrity.sh"
mkdir -p "$artifacts"
if python3 -B "$generator" rebuild-seed --spec "$spec" --seed "$seed" \
--output "$rebuilt" --work "$rebuild_work" \
>"$artifacts/rebuild-seed.json" 2>"$artifacts/rebuild-seed.stderr"; then
:
else
pre15_runner_fail 'B17 tracked seed is not reproducible'
fi
if python3 -B "$generator" generate --spec "$spec" --seed "$seed" \
--output "$first" >"$artifacts/generate-first.json" \
2>"$artifacts/generate-first.stderr"; then
:
else
pre15_runner_fail 'B17 first fixture generation failed'
fi
if python3 -B "$generator" generate --spec "$spec" --seed "$seed" \
--output "$second" >"$artifacts/generate-second.json" \
2>"$artifacts/generate-second.stderr"; then
:
else
pre15_runner_fail 'B17 second fixture generation failed'
fi
if cmp "$first/fixture-index.json" "$second/fixture-index.json" && \
find "$first" -type f ! -name fixture-index.json -printf '%f\n' | sort | \
while IFS= read -r name; do cmp "$first/$name" "$second/$name" || exit 1; done
then
:
else
pre15_runner_fail 'B17 fixture generation is not byte reproducible'
fi
if python3 -B "$oracle" --spec "$spec" --fixtures "$first" \
--report "$artifacts/oracle-first.json" \
>"$artifacts/oracle-first.stdout" 2>"$artifacts/oracle-first.stderr"; then
:
else
pre15_runner_fail 'B17 independent first oracle replay failed'
fi
if python3 -B "$oracle" --spec "$spec" --fixtures "$second" \
--report "$artifacts/oracle-second.json" \
>"$artifacts/oracle-second.stdout" 2>"$artifacts/oracle-second.stderr"; then
:
else
pre15_runner_fail 'B17 independent second oracle replay failed'
fi
cp "$first/fixture-index.json" "$artifacts/B17-fixture-index.json"
pre15_record_fixture b17-generated-index "$artifacts/B17-fixture-index.json"
if python3 - "$artifacts/B17-fixture-index.json" \
"$artifacts/oracle-first.json" "$artifacts/B17-matrix.tsv" <<'PY'
import json
from pathlib import Path
import sys
index = json.loads(Path(sys.argv[1]).read_text(encoding="ascii"))
report = json.loads(Path(sys.argv[2]).read_text(encoding="ascii"))
if index["fixture_count"] != 25 or index["legal_count"] != 10 or index["damaged_count"] != 15:
raise SystemExit("B17 fixture cardinality changed")
if report["status"] != "PASS" or report["legal_passed"] != 10 or report["damaged_passed"] != 15:
raise SystemExit("B17 oracle matrix is incomplete")
lines = ["id\tclass\terrno\treject"]
for item in report["results"]:
lines.append(
f"{item['id']}\t{item['class']}\t{item['actual_errno']}\t{item['actual_reject']}"
)
Path(sys.argv[3]).write_text("\n".join(lines) + "\n", encoding="ascii")
print(
f"B17 fixtures: {index['fixture_count']} "
f"({index['legal_count']} legal, {index['damaged_count']} damaged)"
)
print(f"B17 fixture-set SHA256: {index['fixture_set_sha256']}")
PY
then
:
else
pre15_runner_fail 'B17 fixture matrix summary failed'
fi
pre15_target_reached
if test "$fixtures_only" -eq 1; then
printf '%s\n' 'B17 fixture gate: READY'
exit 0
fi
if python3 - "$PRE15_ROOT" "$PRE15_DUT" "$artifacts/B17-source-check.json" <<'PY'
from pathlib import Path
import json
import subprocess
import sys
root = Path(sys.argv[1])
dut = Path(sys.argv[2])
output = Path(sys.argv[3])
baseline = "98d76e4e73ed9a760b7f684d453b301c73167c22"
def committed(name: str) -> str:
completed = subprocess.run(
["git", "-C", str(root), "show", f"{baseline}:repo-pre-15/src/{name}"],
check=False,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
if completed.returncode != 0:
raise SystemExit(f"cannot read B17 baseline {name}: {completed.stderr}")
return completed.stdout
def replace_once(source: str, old: str, new: str, label: str) -> str:
count = source.count(old)
if count != 1:
raise SystemExit(f"{label}: expected one baseline transform, found {count}")
return source.replace(old, new, 1)
current = {
name: (dut / "src" / name).read_text(encoding="utf-8")
for name in ("internal.h", "super.c", "xattr.c")
}
base = {name: committed(name) for name in current}
expected_internal = replace_once(
base["internal.h"],
"\tuint8_t xattr_prefix_count;\n",
"\tuint8_t xattr_prefix_count;\n\tuint8_t xattr_filter_reserved;\n",
"raw xattr filter state",
)
expected_super = replace_once(
base["super.c"],
"\t/* A non-zero reserved value disables the current name-filter format. */\n"
"\tif (erofs_sb_has_xattr_filter(sbi) && dsb->xattr_filter_reserved != 0)\n"
"\t\tsbi->feature_compat &= ~EROFS_FEATURE_COMPAT_XATTR_FILTER;\n",
"\t/* Preserve the raw feature declaration and gate its format at use sites. */\n"
"\tsbi->xattr_filter_reserved = dsb->xattr_filter_reserved;\n",
"raw feature preservation",
)
expected_xattr = replace_once(
base["xattr.c"],
"\tif (entry_size > remaining)\n\t\treturn (EINTEGRITY);\n",
"\tif (entry_size > remaining)\n\t\treturn (EINTEGRITY);\n"
"\tif (memchr(entry->e_name, '\\0', entry->e_name_len) != NULL)\n"
"\t\treturn (EINTEGRITY);\n",
"inline name NUL validation",
)
expected_xattr = replace_once(
expected_xattr,
"\terror = erofs_xattr_read_backing(sbi, backing_en, off, entry_size,\n"
"\t entrybuf);\n"
"\tif (error != 0)\n"
"\t\treturn (error);\n"
"\tif (entry_sizep != NULL)\n",
"\terror = erofs_xattr_read_backing(sbi, backing_en, off, entry_size,\n"
"\t entrybuf);\n"
"\tif (error != 0)\n"
"\t\treturn (error);\n"
"\terror = erofs_xattr_validate_entry(entrybuf->data, entry_size, NULL,\n"
"\t value_sizep);\n"
"\tif (error != 0) {\n"
"\t\terofs_put_metabuf(entrybuf);\n"
"\t\treturn (error);\n"
"\t}\n"
"\tif (entry_sizep != NULL)\n",
"shared name NUL validation",
)
expected_xattr = replace_once(
expected_xattr,
"\tif (!erofs_sb_has_xattr_filter(sbi))\n\t\treturn (0);\n",
"\tif (!erofs_sb_has_xattr_filter(sbi) ||\n"
"\t sbi->xattr_filter_reserved != 0)\n"
"\t\treturn (0);\n",
"xattr filter use-site gate",
)
expected_xattr = replace_once(
expected_xattr,
"\t\tprefix = buf.data;\n"
"\t\tinfix_len = len - sizeof(*prefix);\n"
"\t\tsbi->xattr_prefixes[i].base_index = prefix->base_index;\n",
"\t\tprefix = buf.data;\n"
"\t\tinfix_len = len - sizeof(*prefix);\n"
"\t\tif (memchr(prefix->infix, '\\0', infix_len) != NULL) {\n"
"\t\t\terror = EINTEGRITY;\n"
"\t\t\tgoto fail;\n"
"\t\t}\n"
"\t\tsbi->xattr_prefixes[i].base_index = prefix->base_index;\n",
"long-prefix NUL validation",
)
expected = {
"internal.h": expected_internal,
"super.c": expected_super,
"xattr.c": expected_xattr,
}
for name in expected:
if current[name] != expected[name]:
raise SystemExit(f"{name} differs from the exact B17 ledger transforms")
diff = subprocess.run(
["git", "-C", str(root), "diff", baseline, "--", "repo-pre-15/src/internal.h",
"repo-pre-15/src/super.c", "repo-pre-15/src/xattr.c"],
check=True,
text=True,
stdout=subprocess.PIPE,
).stdout
for forbidden in ("xxh32", "bloom", "cache owner", "cache waiter"):
if forbidden in diff.lower():
raise SystemExit(f"B17 source diff contains out-of-scope marker: {forbidden}")
if "return (-E" in "".join(current.values()):
raise SystemExit("negative errno entered the FreeBSD B17 source")
result = {
"status": "PASS",
"baseline": baseline,
"changed_sources": sorted(expected),
"raw_feature_preserved": True,
"reserved_gated_at_use": True,
"inline_name_nul": True,
"shared_name_nul": True,
"prefix_infix_nul": True,
"acl_empty_suffix_preserved": True,
}
output.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n", encoding="ascii")
print("B17 source: exact raw-feature and name-integrity transforms present")
PY
then
:
else
pre15_dut_fail 'B17 source does not match the fixture-authorized transforms'
fi
printf '%s\n' 'B17 source gate: PASS'