mirror of
https://github.com/Astatin3/CC2.git
synced 2026-06-08 16:08:00 -06:00
Sucessfully repack OTA!
This commit is contained in:
Executable
+58
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 || $# -gt 2 ]]; then
|
||||
printf 'Usage: %s input-dir [output.zip]\n' "$0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
indir=$1
|
||||
output=${2:-release.zip}
|
||||
|
||||
python3 - "$indir" "$output" <<'PY'
|
||||
import pathlib
|
||||
import stat
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
|
||||
def fail(message):
|
||||
print(message, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
fail("Usage: build-release-zip.sh input-dir [output.zip]")
|
||||
|
||||
root = pathlib.Path(sys.argv[1])
|
||||
output = pathlib.Path(sys.argv[2])
|
||||
|
||||
if not root.is_dir():
|
||||
fail(f"input directory does not exist: {root}")
|
||||
|
||||
entries = sorted(path for path in root.iterdir() if path.is_file())
|
||||
if not entries:
|
||||
fail(f"input directory contains no regular files: {root}")
|
||||
|
||||
|
||||
def zip_date_time(path):
|
||||
modified = path.stat().st_mtime
|
||||
return tuple(__import__("time").localtime(modified)[:6])
|
||||
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zipfile.ZipFile(output, "w") as archive:
|
||||
for src in entries:
|
||||
mode = stat.S_IMODE(src.stat().st_mode)
|
||||
info = zipfile.ZipInfo(src.name, date_time=zip_date_time(src))
|
||||
info.create_system = 3
|
||||
info.external_attr = (stat.S_IFREG | mode) << 16
|
||||
info.compress_type = zipfile.ZIP_DEFLATED
|
||||
archive.writestr(
|
||||
info,
|
||||
src.read_bytes(),
|
||||
compress_type=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=6,
|
||||
)
|
||||
|
||||
print(f"wrote {output}")
|
||||
PY
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 || $# -gt 2 ]]; then
|
||||
printf 'Usage: %s unpacked-dir [output.zip.sig]\n' "$0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
workdir=$1
|
||||
output=${2:-$workdir/repacked.zip.sig}
|
||||
env_file="$workdir/repack.env"
|
||||
|
||||
if [[ ! -f "$env_file" ]]; then
|
||||
printf 'missing repack metadata: %s\n' "$env_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$env_file"
|
||||
|
||||
required=(
|
||||
"$workdir/templates/release.zip.sig"
|
||||
"$workdir/templates/$SWU_SIG_NAME"
|
||||
"$workdir/templates/$OTA_SIG_NAME"
|
||||
"$workdir/release-signed/$SWU_SIG_NAME"
|
||||
"$workdir/release-signed/$OTA_SIG_NAME"
|
||||
"$workdir/release/$OTA_NAME"
|
||||
"$workdir/swu/.swu-manifest.json"
|
||||
)
|
||||
|
||||
for path in "${required[@]}"; do
|
||||
if [[ ! -e "$path" ]]; then
|
||||
printf 'missing required repack input: %s\n' "$path" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
cargo build --quiet
|
||||
|
||||
sig_bin=target/debug/sig
|
||||
build_dir="$workdir/build"
|
||||
release_dir="$build_dir/release"
|
||||
rebuilt_swu="$build_dir/$SWU_NAME"
|
||||
rebuilt_ota="$build_dir/$OTA_NAME"
|
||||
rebuilt_zip="$build_dir/$ZIP_NAME"
|
||||
|
||||
rm -rf "$build_dir"
|
||||
mkdir -p "$release_dir"
|
||||
|
||||
scripts/build-swu.sh "$workdir/swu" "$rebuilt_swu"
|
||||
"$sig_bin" repack "$rebuilt_swu" --template "$workdir/templates/$SWU_SIG_NAME" -o "$release_dir/$SWU_SIG_NAME"
|
||||
cp "$workdir/release/$OTA_NAME" "$rebuilt_ota"
|
||||
|
||||
python3 - "$rebuilt_ota" "$workdir/release/$OTA_NAME" "$release_dir/$SWU_SIG_NAME" "$SWU_SIG_NAME" <<'PY'
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
ota_path = pathlib.Path(sys.argv[1])
|
||||
source_ota_path = pathlib.Path(sys.argv[2])
|
||||
swu_sig_path = pathlib.Path(sys.argv[3])
|
||||
swu_sig_name = sys.argv[4]
|
||||
|
||||
data = json.loads(ota_path.read_text())
|
||||
digest = hashlib.sha256(swu_sig_path.read_bytes()).hexdigest()
|
||||
matched = False
|
||||
for package in data.get("packages", []):
|
||||
if package.get("file") == swu_sig_name:
|
||||
package["hash"] = digest
|
||||
matched = True
|
||||
|
||||
if not matched:
|
||||
raise SystemExit(f"ota package list does not reference {swu_sig_name}")
|
||||
|
||||
updated = json.dumps(data, separators=(", ", ": "))
|
||||
ota_path.write_text(updated)
|
||||
source_ota_path.write_text(updated)
|
||||
PY
|
||||
|
||||
"$sig_bin" repack "$rebuilt_ota" --template "$workdir/templates/$OTA_SIG_NAME" -o "$release_dir/$OTA_SIG_NAME"
|
||||
|
||||
touch -r "$workdir/release-signed/$SWU_SIG_NAME" "$release_dir/$SWU_SIG_NAME"
|
||||
touch -r "$workdir/release-signed/$OTA_SIG_NAME" "$release_dir/$OTA_SIG_NAME"
|
||||
chmod --reference="$workdir/release-signed/$SWU_SIG_NAME" "$release_dir/$SWU_SIG_NAME"
|
||||
chmod --reference="$workdir/release-signed/$OTA_SIG_NAME" "$release_dir/$OTA_SIG_NAME"
|
||||
|
||||
scripts/build-release-zip.sh "$release_dir" "$rebuilt_zip"
|
||||
"$sig_bin" repack "$rebuilt_zip" --template "$workdir/templates/release.zip.sig" -o "$output"
|
||||
|
||||
printf 'rebuilt %s\n' "$output"
|
||||
|
||||
if [[ -n "${ORIGINAL_SIG:-}" && -f "$ORIGINAL_SIG" ]]; then
|
||||
if cmp -s "$output" "$ORIGINAL_SIG"; then
|
||||
printf 'bit-perfect match: %s\n' "$ORIGINAL_SIG"
|
||||
else
|
||||
printf 'warning: rebuilt output differs from %s\n' "$ORIGINAL_SIG" >&2
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
Executable
+79
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 || $# -gt 2 ]]; then
|
||||
printf 'Usage: %s input.zip.sig [output-dir]\n' "$0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
input=$1
|
||||
outdir=${2:-release-unpacked}
|
||||
|
||||
if [[ ! -f "$input" ]]; then
|
||||
printf 'input does not exist: %s\n' "$input" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -e "$outdir" && -n "$(ls -A "$outdir")" ]]; then
|
||||
printf 'output directory is not empty: %s\n' "$outdir" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$outdir" "$outdir/templates" "$outdir/release-signed" "$outdir/release" "$outdir/swu"
|
||||
|
||||
cargo build --quiet
|
||||
|
||||
sig_bin=target/debug/sig
|
||||
base=$(basename "$input")
|
||||
zip_name=${base%.sig}
|
||||
zip_path="$outdir/$zip_name"
|
||||
|
||||
cp -p "$input" "$outdir/templates/release.zip.sig"
|
||||
"$sig_bin" unpack "$input" -o "$zip_path"
|
||||
unzip -q "$zip_path" -d "$outdir/release-signed"
|
||||
|
||||
mapfile -t signed_files < <(python3 - "$zip_path" <<'PY'
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
with zipfile.ZipFile(sys.argv[1]) as archive:
|
||||
for item in archive.infolist():
|
||||
if not item.is_dir():
|
||||
print(item.filename)
|
||||
PY
|
||||
)
|
||||
|
||||
swu_sig_name=''
|
||||
ota_sig_name=''
|
||||
for name in "${signed_files[@]}"; do
|
||||
case "$name" in
|
||||
*.swu.sig) swu_sig_name=$name ;;
|
||||
ota-package-list.json.sig) ota_sig_name=$name ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$swu_sig_name" || -z "$ota_sig_name" ]]; then
|
||||
printf 'release zip must contain one .swu.sig and ota-package-list.json.sig\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
swu_name=${swu_sig_name%.sig}
|
||||
ota_name=${ota_sig_name%.sig}
|
||||
|
||||
cp -p "$outdir/release-signed/$swu_sig_name" "$outdir/templates/$swu_sig_name"
|
||||
cp -p "$outdir/release-signed/$ota_sig_name" "$outdir/templates/$ota_sig_name"
|
||||
|
||||
"$sig_bin" unpack "$outdir/release-signed/$swu_sig_name" -o "$outdir/release/$swu_name"
|
||||
"$sig_bin" unpack "$outdir/release-signed/$ota_sig_name" -o "$outdir/release/$ota_name"
|
||||
scripts/extract-swu.sh "$outdir/release/$swu_name" "$outdir/swu"
|
||||
|
||||
cat > "$outdir/repack.env" <<EOF
|
||||
ORIGINAL_SIG=$input
|
||||
ZIP_NAME=$zip_name
|
||||
SWU_SIG_NAME=$swu_sig_name
|
||||
SWU_NAME=$swu_name
|
||||
OTA_SIG_NAME=$ota_sig_name
|
||||
OTA_NAME=$ota_name
|
||||
EOF
|
||||
|
||||
printf 'unpacked %s to %s\n' "$input" "$outdir"
|
||||
Reference in New Issue
Block a user