Skip to content

Commit a894e49

Browse files
feat(controller): backup writer stamps a device-backup identity manifest
App-created backups now embed installed-rootfs/iiab/.iiab-rootfs.json declaring kind/arch + origin=device-backup (and builder=knowledgetogo-app). Staged in a temp tree and packed FIRST (a second tar -C) so the validator reads it from the first header — no full decompress, no java.nio, flag-agnostic. NO treehash is computed on the device (we don't make the phone a builder); origin=device-backup is the explicit no-checksum declaration the verifier maps to OK_NO_CHECKSUM.
1 parent 3c97ca6 commit a894e49

1 file changed

Lines changed: 36 additions & 1 deletion

File tree

‎controller/app/src/main/java/org/iiab/controller/DeployFragment.java‎

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1909,9 +1909,44 @@ private void bindBackupButtonLogic(MainActivity mainAct, File backupsDir, File i
19091909
String tarBin = staticTar.exists() ? staticTar.getAbsolutePath() : "tar";
19101910
String gzipBin = staticGzip.exists() ? staticGzip.getAbsolutePath() : "gzip";
19111911

1912+
// Stamp an identity manifest into the backup so a re-import is
1913+
// recognized (kind/arch) AND explicitly declares it carries NO
1914+
// integrity checksum (origin=device-backup) — we do NOT turn the
1915+
// phone into a builder. It is staged in a temp tree and packed
1916+
// FIRST (a second `-C`) so RootfsArchiveValidator reads it from
1917+
// the first tar header without decompressing the whole archive.
1918+
// See docs/ROOTFS_MANIFEST.md.
1919+
String manifestArg = null;
1920+
File mfStageRoot = new File(requireContext().getCacheDir(), "mfstage");
1921+
try {
1922+
if (mfStageRoot.exists()) {
1923+
ProcessRunner.run(new String[]{"rm", "-rf", mfStageRoot.getAbsolutePath()});
1924+
}
1925+
File iiabStage = new File(mfStageRoot, "installed-rootfs/iiab");
1926+
if (iiabStage.mkdirs()) {
1927+
String appAbi = org.iiab.controller.deploy.data.RootfsManifest.appAbiId();
1928+
String debArch = appAbi.contains("64") ? "arm64" : "armhf";
1929+
String built = String.format(java.util.Locale.US, "%04d.%03d", year, dayOfYear);
1930+
String identityJson = "{\"schema\":1,\"kind\":\"iiab-rootfs\",\"arch\":\""
1931+
+ appAbi + "\",\"deb_arch\":\"" + debArch + "\",\"built\":\""
1932+
+ built + "\",\"builder\":\"knowledgetogo-app\",\"origin\":\"device-backup\"}";
1933+
java.io.FileOutputStream mfo =
1934+
new java.io.FileOutputStream(new File(iiabStage, ".iiab-rootfs.json"));
1935+
mfo.write(identityJson.getBytes("UTF-8"));
1936+
mfo.close();
1937+
manifestArg = "-C '" + mfStageRoot.getAbsolutePath()
1938+
+ "' 'installed-rootfs/iiab/.iiab-rootfs.json' ";
1939+
}
1940+
} catch (Exception mfe) {
1941+
Log.w(TAG, "Could not stage identity manifest for backup: " + mfe.getMessage());
1942+
manifestArg = null;
1943+
}
1944+
19121945
// D11: single-quote the interpolated paths so the backup pipe is robust
19131946
// even if a path ever contains spaces/metacharacters (app-internal today).
1914-
String cmd = "'" + tarBin + "' -cf - -C '" + iiabRootDir.getAbsolutePath()
1947+
String cmd = "'" + tarBin + "' -cf - "
1948+
+ (manifestArg != null ? manifestArg : "")
1949+
+ "-C '" + iiabRootDir.getAbsolutePath()
19151950
+ "' installed-rootfs | '" + gzipBin + "' > '" + backupFile.getAbsolutePath() + "'";
19161951
// D12: ProcessRunner drains stderr so a large backup with tar warnings
19171952
// cannot deadlock on a full pipe buffer.

0 commit comments

Comments
 (0)