Fix Patchless for cloudOS 26.4#336
Conversation
|
cool, testing it now, 26.4 has a problem with the ramdisk in 26.4 with the other variants, that I am trying to solve, but it seems that this is not a limiting factor to the patchless variant. |
|
Wow thank you for this lightning fast review. I just noticed that I forgot to push one part. Give me one second 😅 |
|
there seem to be an issue in the restore stage: |
b4e6367 to
1ca38d5
Compare
|
Ok, now the filesystem patcher is also using the right |
by dynamically matching and downloading the required apfs_sealvolume version.
1ca38d5 to
c354720
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates the patchless (“less”) firmware workflow to use a version-specific apfs_sealvolume binary, addressing incompatibilities between cloudOS 26.3 vs 26.4 APFS sealing behavior.
Changes:
- Select
apfs_sealvolumedynamically based onProductVersionfromBuildManifest.plistduring filesystem patching. - Move
apfs_sealvolumeacquisition intofw_prepare.sh, downloading and resigning a version-matched binary for the patchless variant. - Simplify setup flow by removing the old
setup_tools.shsealvolume step and adjustingsetup_machine.shto pass the patchless variant throughfw_prepare.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
| sources/FirmwarePatcher/Filesystem/CryptexFilesystemPatcher.swift | Switches filesystem sealing to a versioned apfs_sealvolume path derived from ProductVersion. |
| scripts/setup_tools.sh | Removes the previous patchless-only sealvolume download step and updates step counters. |
| scripts/setup_machine.sh | Ensures patchless runs fw_prepare with VARIANT=less so required tooling can be fetched there. |
| scripts/fw_prepare.sh | Adds logic to download a version-matched apfs_sealvolume from a macOS restore and place it in .tools/. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func identify_apfs_sealvolume() throws -> URL { | ||
| let iosVersion = try getProductVersion() | ||
| return self.vphoneCliDirectory.appending(path: ".tools/apfs_sealvolume_\(iosVersion)") | ||
| } |
| func identify_apfs_sealvolume() throws -> URL { | ||
| let iosVersion = try getProductVersion() | ||
| return self.vphoneCliDirectory.appending(path: ".tools/apfs_sealvolume_\(iosVersion)") | ||
| } | ||
|
|
| } | ||
|
|
||
| func getProductVersion() throws -> String { | ||
| var root = try parsePlist(data: buildManiest) |
| local src="$1" | ||
| IOS_VERSION="$(basename "$src" | awk -F_ '{print $2}')" | ||
| filename="apfs_sealvolume_$IOS_VERSION" | ||
|
|
| ipsw download appledb \ | ||
| --os macOS \ | ||
| --build $BUILD \ | ||
| --pattern "^BuildManifest.plist\$" \ | ||
| --output "$TMP_DIR" |
| IOS_VERSION="$(basename "$src" | awk -F_ '{print $2}')" | ||
| filename="apfs_sealvolume_$IOS_VERSION" | ||
|
|
||
| PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" | ||
| TOOLS_PREFIX="$PROJECT_DIR/.tools" | ||
|
|
|
|
||
| [[ "$ver" == "$IOS_VERSION" ]] || continue | ||
|
|
||
| selected_src="$url" |
| TMP_DIR="$(mktemp -d)" | ||
|
|
||
| # List matching macOS version to the iOS version | ||
| while IFS= read -r url; do | ||
| bn="$(basename "$url")" | ||
| ver="${bn#*_}" | ||
| ver="${ver%%_*}" | ||
|
|
||
| [[ "$ver" == "$IOS_VERSION" ]] || continue | ||
|
|
||
| selected_src="$url" | ||
| BUILD="$(awk -F_ '{print $3}' <<<"$bn")" | ||
| break | ||
| done < <( | ||
| ipsw download appledb \ | ||
| --os macOS \ | ||
| --version $IOS_VERSION \ | ||
| --urls | ||
| ) | ||
|
|
||
| # Download BuildManifest first | ||
| ipsw download appledb \ | ||
| --os macOS \ | ||
| --build $BUILD \ | ||
| --pattern "^BuildManifest.plist\$" \ | ||
| --output "$TMP_DIR" | ||
|
|
||
| BUILD_MANIFEST="$(find "$TMP_DIR" -name BuildManifest.plist -print -quit)" | ||
| if [ -z "$BUILD_MANIFEST" ]; then | ||
| echo "Failed to locate BuildManifest.plist" | ||
| rm -rf "$TMP_DIR" | ||
| exit 1 | ||
| fi | ||
|
|
||
| RAMDISK_PATH="$(/usr/bin/plutil -extract 'BuildIdentities.0.Manifest.RestoreRamDisk.Info.Path' raw -o - "$BUILD_MANIFEST")" | ||
| if [ -z "$RAMDISK_PATH" ]; then | ||
| echo "Failed to read RestoreRamDisk path from BuildManifest" | ||
| rm -rf "$TMP_DIR" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Download the ramdisk referenced by BuildManifest | ||
| ipsw download appledb \ | ||
| --os macOS \ | ||
| --build $BUILD \ | ||
| --pattern "$RAMDISK_PATH" \ | ||
| --output "$TMP_DIR" | ||
|
|
||
| RAMDISK_IM4P="$(find "$TMP_DIR" -path "*${RAMDISK_PATH}" -print -quit)" | ||
| if [ -z "$RAMDISK_IM4P" ]; then | ||
| echo "Failed to locate downloaded ramdisk: $RAMDISK_PATH" | ||
| rm -rf "$TMP_DIR" | ||
| exit 1 | ||
| fi | ||
|
|
||
| RAMDISK="$TMP_DIR/ramdisk.dmg" | ||
| ipsw img4 im4p extract --output "$RAMDISK" "$RAMDISK_IM4P" | ||
|
|
||
| MOUNT=$(hdiutil attach -readonly -nobrowse "$RAMDISK" | awk 'END{ print$NF}') | ||
| cp "$MOUNT/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs_sealvolume" \ | ||
| "$TOOLS_PREFIX/$filename" | ||
| hdiutil detach "$MOUNT" >/dev/null 2>&1 || true | ||
| rm -rf "$TMP_DIR" |
There was a problem hiding this comment.
true, I experienced this in my testing
| RAMDISK="$TMP_DIR/ramdisk.dmg" | ||
| ipsw img4 im4p extract --output "$RAMDISK" "$RAMDISK_IM4P" | ||
|
|
||
| MOUNT=$(hdiutil attach -readonly -nobrowse "$RAMDISK" | awk 'END{ print$NF}') | ||
| cp "$MOUNT/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs_sealvolume" \ | ||
| "$TOOLS_PREFIX/$filename" | ||
| hdiutil detach "$MOUNT" >/dev/null 2>&1 || true | ||
| rm -rf "$TMP_DIR" |
There was a problem hiding this comment.
true, I experienced this in my testing
| VARIANT="${VARIANT:-}" | ||
| if [[ "$VARIANT" == "less" ]]; then | ||
| download_apfs_sealvolume "$IPHONE_SOURCE" | ||
| else | ||
| echo "==> Downloading apfs sealvolume (skipped — patchless variant only)" |
|
I encountered some weird behavior with the patchless variant when you originally added it. |
|
at any case, I tested the branch and it works, look over the CR comments left by Copilot and after you resolve/dismiss them we can merge. |
by dynamically matching and downloading the required apfs_sealvolume version.
We find that
apfs_sealvolumeis more version dependent than expected.A 26.3
apfs_sealvolumedoes not work with a 26.4 filesystem and vice versa.