address review: validate reused disc data, fingerprint osx deployment target

This commit is contained in:
patchzyy
2026-10-18 17:12:31 +02:00
parent 4ae883ec84
commit 7d048d604b
3 changed files with 36 additions and 11 deletions
+17 -3
View File
@@ -68,7 +68,7 @@ internal static class DiscTool
Directory.CreateDirectory(assetsDirectory);
File.Copy(dolPath, Path.Combine(assetsDirectory, "main.dol"), overwrite: true);
File.Copy(relPath, Path.Combine(assetsDirectory, "StaticR.rel"), overwrite: true);
File.WriteAllText(Path.Combine(assetsDirectory, ExtractionMarker), dolSha);
File.WriteAllText(Path.Combine(assetsDirectory, ExtractionMarker), ExtractionRecord(dolSha, dataDir));
reporter.Progress(InstallStages.ExtractDisc, "Disc validated and extracted", 6);
}
@@ -102,14 +102,28 @@ internal static class DiscTool
var marker = Path.Combine(assetsDirectory, ExtractionMarker);
var dol = Path.Combine(assetsDirectory, "main.dol");
var rel = Path.Combine(assetsDirectory, "StaticR.rel");
var dataDir = Path.Combine(assetsDirectory, "DATA");
if (!File.Exists(marker) || !File.Exists(dol) || !File.Exists(rel) ||
!Directory.Exists(Path.Combine(assetsDirectory, "DATA", "files")))
!Directory.Exists(Path.Combine(dataDir, "files")))
return false;
return string.Equals(File.ReadAllText(marker).Trim(), manifest.DolSha256, StringComparison.Ordinal) &&
return string.Equals(File.ReadAllText(marker), ExtractionRecord(manifest.DolSha256, dataDir),
StringComparison.Ordinal) &&
string.Equals(Sha256Of(dol), manifest.DolSha256, StringComparison.Ordinal) &&
string.Equals(Sha256Of(rel), manifest.RelSha256, StringComparison.Ordinal);
}
// The DOL hash plus every extracted file's path and size, so a later deletion or truncation inside
// DATA forces a fresh extraction.
private static string ExtractionRecord(string dolSha, string dataDir)
{
var record = new System.Text.StringBuilder(dolSha).Append('\n');
foreach (var path in Directory.EnumerateFiles(dataDir, "*", SearchOption.AllDirectories)
.Select(path => Path.GetRelativePath(dataDir, path).Replace('\\', '/'))
.Order(StringComparer.Ordinal))
record.Append(new FileInfo(Path.Combine(dataDir, path)).Length).Append(' ').Append(path).Append('\n');
return record.ToString();
}
private static string Sha256Of(string path)
{
using var stream = File.OpenRead(path);
+10 -5
View File
@@ -39,9 +39,12 @@ done
assets_dir=$(mkdir -p "$assets_dir" && cd "$assets_dir" && pwd)
# DATA is published before main.dol and StaticR.rel, so verified files imply a complete extraction.
if [[ -d "$assets_dir/DATA/files" && -f "$assets_dir/main.dol" && -f "$assets_dir/StaticR.rel" ]] && \
[[ $(sha256 "$assets_dir/main.dol") == "$EXPECTED_DOL_SHA256" && $(sha256 "$assets_dir/StaticR.rel") == "$EXPECTED_REL_SHA256" ]]; then
# Sorted "<size> <path>" of every extracted file; recorded at extraction, compared on reuse.
data_manifest() { (cd "$1" && find . -type f -print0 | LC_ALL=C sort -z | xargs -0 stat -f '%z %N'); }
if [[ -d "$assets_dir/DATA/files" && -f "$assets_dir/.data-manifest" && -f "$assets_dir/main.dol" && -f "$assets_dir/StaticR.rel" ]] && \
[[ $(sha256 "$assets_dir/main.dol") == "$EXPECTED_DOL_SHA256" && $(sha256 "$assets_dir/StaticR.rel") == "$EXPECTED_REL_SHA256" ]] && \
[[ "$(data_manifest "$assets_dir/DATA")" == "$(cat "$assets_dir/.data-manifest")" ]]; then
printf 'MKWCBUILD:STEP:disc-ready Reusing the verified extracted game assets\n'
exit 0
fi
@@ -73,15 +76,17 @@ mkdir -p "$stage"
ditto "$data_root" "$stage/DATA"
ditto "$dol" "$stage/main.dol"
ditto "$rel" "$stage/StaticR.rel"
data_manifest "$stage/DATA" > "$stage/.data-manifest"
backup="$assets_dir/.previous-extraction-$(date +%Y%m%d-%H%M%S)"
if [[ -e "$assets_dir/DATA" || -e "$assets_dir/main.dol" || -e "$assets_dir/StaticR.rel" ]]; then
if [[ -e "$assets_dir/DATA" || -e "$assets_dir/.data-manifest" || -e "$assets_dir/main.dol" || -e "$assets_dir/StaticR.rel" ]]; then
mkdir -p "$backup"
for item in DATA main.dol StaticR.rel; do
for item in DATA .data-manifest main.dol StaticR.rel; do
[[ -e "$assets_dir/$item" ]] && mv "$assets_dir/$item" "$backup/$item"
done
fi
mv "$stage/DATA" "$assets_dir/DATA"
mv "$stage/.data-manifest" "$assets_dir/.data-manifest"
mv "$stage/main.dol" "$assets_dir/main.dol"
mv "$stage/StaticR.rel" "$assets_dir/StaticR.rel"
rmdir "$stage"
+9 -3
View File
@@ -2,11 +2,13 @@
# a precompiled runtime archive may replace compiling it. Script mode prints
# exactly one stdout line, runtime_fingerprint=<sha256 hex>:
# cmake -DMKW_RUNTIME_DIR=<abs runtime dir> [-DMKW_CPPWINRT_INCLUDE_DIR=<dir>]
# [-DMKW_X86_CPU_PROFILE=v2|v3] -P runtime/cmake/RuntimeFingerprint.cmake
# [-DMKW_X86_CPU_PROFILE=v2|v3] [-DCMAKE_OSX_DEPLOYMENT_TARGET=<ver>]
# -P runtime/cmake/RuntimeFingerprint.cmake
#
# Inputs: src/, include/, cmake/ and CMakeLists.txt (sorted relative paths and
# content hashes), winrt/base.h and the CPU profile. third_party/ has its own
# package fingerprint; game/ is per-user. Dot-files differ between machines.
# content hashes), winrt/base.h, the CPU profile and the macOS deployment target.
# third_party/ has its own package fingerprint; game/ is per-user. Dot-files
# differ between machines.
function(mkw_runtime_fingerprint_inputs out_var runtime_dir)
get_filename_component(_root "${runtime_dir}" ABSOLUTE)
@@ -37,6 +39,10 @@ function(mkw_runtime_fingerprint out_var runtime_dir cppwinrt_dir cpu_profile)
string(APPEND _manifest "cppwinrt:winrt/base.h ${_hash}\n")
endif()
string(APPEND _manifest "x86_cpu_profile ${cpu_profile}\n")
# Omitted when empty so Windows and Linux fingerprints are unaffected.
if(CMAKE_OSX_DEPLOYMENT_TARGET)
string(APPEND _manifest "osx_deployment_target ${CMAKE_OSX_DEPLOYMENT_TARGET}\n")
endif()
string(SHA256 _fingerprint "${_manifest}")
set(${out_var} "${_fingerprint}" PARENT_SCOPE)
endfunction()