From 1ba97938ff97170b8d7be5dff6819ba36aadc234 Mon Sep 17 00:00:00 2001 From: cfig Date: Tue, 20 May 2025 09:16:59 +0800 Subject: [PATCH] staging --- bbootimg/src/main/kotlin/bootimg/Common.kt | 45 ++++++++++++++----- bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt | 16 +++---- .../src/main/kotlin/bootimg/v3/VendorBoot.kt | 4 +- .../main/kotlin/packable/DeviceTreeParser.kt | 41 +++++++++++++---- .../src/main/kotlin/packable/VBMetaParser.kt | 7 +-- .../main/kotlin/packable/VendorBootParser.kt | 1 + .../src/main/kotlin/rom/sparse/SparseImage.kt | 13 +++--- .../main/kotlin/rom/sparse/SparseImgParser.kt | 31 +++++++++++++ 8 files changed, 121 insertions(+), 37 deletions(-) diff --git a/bbootimg/src/main/kotlin/bootimg/Common.kt b/bbootimg/src/main/kotlin/bootimg/Common.kt index aa1b0c7..6a58cea 100644 --- a/bbootimg/src/main/kotlin/bootimg/Common.kt +++ b/bbootimg/src/main/kotlin/bootimg/Common.kt @@ -525,23 +525,46 @@ class Common { } } - fun createWorkspaceIni(fileName: String) { - //create workspace file - val workspaceFile = File(Helper.prop("workDir"), "workspace.ini").canonicalPath + fun createWorkspaceIni(fileName: String, iniFileName: String = "workspace.ini", prefix: String? = null) { + log.trace("create workspace file") + val workDir = Helper.prop("workDir") + val workspaceFile = File(workDir, iniFileName) + try { - FileOutputStream(workspaceFile).use { output -> - Properties().also { - it.setProperty("file", fileName) - it.setProperty("workDir", Helper.prop("workDir")) - it.setProperty("role", File(fileName).name) - it.store(output, "unpackInternal configuration") + if (prefix.isNullOrBlank()) { + // override existing file entirely when prefix is null or empty + val props = Properties().apply { + setProperty("file", fileName) + setProperty("workDir", workDir) + setProperty("role", File(fileName).name) + } + FileOutputStream(workspaceFile).use { out -> + props.store(out, "unpackInternal configuration (overridden)") + } + log.info("workspace file overridden: ${workspaceFile.canonicalPath}") + } else { + // merge into existing (or create new) with prefixed keys + val props = Properties().apply { + if (workspaceFile.exists()) { + FileInputStream(workspaceFile).use { load(it) } + } } - log.info("workspace file created: $workspaceFile") + + fun key(name: String) = "${prefix.trim()}.$name" + props.setProperty(key("file"), fileName) + props.setProperty(key("workDir"), workDir) + props.setProperty(key("role"), File(fileName).name) + + FileOutputStream(workspaceFile).use { out -> + props.store(out, "unpackInternal configuration (with prefix='$prefix')") + } + log.info("workspace file created/updated with prefix '$prefix': ${workspaceFile.canonicalPath}") } } catch (e: IOException) { log.error("error writing workspace file: ${e.message}") } - //create workspace file done + + log.trace("create workspace file done") } } } diff --git a/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt b/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt index 7345f2f..6fbb990 100644 --- a/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt +++ b/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt @@ -300,8 +300,8 @@ data class BootV2( "verify fail" } Avb.getJsonFileName(info.output).let { jsonFile -> - it.addRow("AVB info [$verifyStatus]", jsonFile) - prints.add(Pair("AVB info [$verifyStatus]", jsonFile)) + it.addRow("AVB info [$verifyStatus]", shortenPath(jsonFile)) + prints.add(Pair("AVB info [$verifyStatus]", shortenPath(jsonFile))) if (File(jsonFile).exists()) { mapper.readValue(File(jsonFile), AVBInfo::class.java).let { ai -> val inspectRet = Avb.inspectKey(ai) @@ -362,11 +362,11 @@ data class BootV2( if (theDtb.size > 0) { val dtbCount = this.dtb!!.dtbList.size it.addRule() - it.addRow("dtb", theDtb.file) - prints.add(Pair("dtb", theDtb.file.toString())) + it.addRow("dtb", theDtb.file?.let { fullPath -> shortenPath(fullPath) }) + prints.add(Pair("dtb", shortenPath(theDtb.file.toString()))) if (File(theDtb.file + ".0.${dtsSuffix}").exists()) { - it.addRow("\\-- decompiled dts [$dtbCount]", theDtb.file + ".*.${dtsSuffix}") - prints.add(Pair("\\-- decompiled dts [$dtbCount]", theDtb.file + ".*.${dtsSuffix}")) + it.addRow("\\-- decompiled dts [$dtbCount]", shortenPath(theDtb.file + ".*.${dtsSuffix}")) + prints.add(Pair("\\-- decompiled dts [$dtbCount]", shortenPath(theDtb.file + ".*.${dtsSuffix}"))) } } } @@ -377,8 +377,8 @@ data class BootV2( val tabVBMeta = AsciiTable().let { if (File("vbmeta.img").exists()) { it.addRule() - it.addRow("vbmeta.img", Avb.getJsonFileName("vbmeta.img")) - prints.add(Pair("vbmeta.img", Avb.getJsonFileName("vbmeta.img"))) + it.addRow("vbmeta.img", shortenPath(Avb.getJsonFileName("vbmeta.img"))) + prints.add(Pair("vbmeta.img", shortenPath(Avb.getJsonFileName("vbmeta.img")))) it.addRule() "\n" + it.render() } else { diff --git a/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt b/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt index 04ba1dc..8d8c957 100644 --- a/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt +++ b/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt @@ -341,7 +341,9 @@ data class VendorBoot( } fun postCopy(outFile: String): VendorBoot { - val signedFile = Helper.joinPath(Helper.prop("intermediateDir")!!, this.info.role + ".signed") + val dir = Helper.prop("intermediateDir")!! + val signedFile = Helper.joinPath(dir, "${info.role}.signed").takeIf { File(it).exists() } + ?: Helper.joinPath(dir, "${info.role}.clear") log.info("COPY $signedFile -> $outFile") File(signedFile).copyTo(File(outFile), overwrite = true) return this diff --git a/bbootimg/src/main/kotlin/packable/DeviceTreeParser.kt b/bbootimg/src/main/kotlin/packable/DeviceTreeParser.kt index a72419f..db14255 100644 --- a/bbootimg/src/main/kotlin/packable/DeviceTreeParser.kt +++ b/bbootimg/src/main/kotlin/packable/DeviceTreeParser.kt @@ -1,6 +1,7 @@ package packable import cfig.bootimg.Common +import cfig.bootimg.v3.VendorBoot import cfig.helper.Helper import cfig.helper.Helper.Companion.check_call import cfig.helper.Helper.Companion.check_output @@ -15,13 +16,24 @@ class DeviceTreeParser : IPackable { override fun capabilities(): List { return listOf("^.*\\.dtb$") } + override val loopNo: Int get() = 1 override fun unpack(fileName: String) { - super.clear() - log.info("unpacking $fileName") - val outFile = workDir + fileName.removeSuffix(".dtb") + "." + Helper.prop("config.dts_suffix") + unpackInternal(fileName, Helper.prop("workDir")!!) + } + + fun unpackInternal(fileName: String, unpackDir: String) { + //set workdir + log.info("unpackInternal(fileName: $fileName, unpackDir: $unpackDir)") + Helper.setProp("workDir", unpackDir) + clear() + //create workspace file + Common.createWorkspaceIni(fileName) + //create workspace file done + + val outFile = File(workDir, File(fileName).nameWithoutExtension + "." + Helper.prop("config.dts_suffix")).path DTC().decompile(fileName, outFile) //print summary @@ -32,15 +44,26 @@ class DeviceTreeParser : IPackable { } override fun pack(fileName: String) { - log.info("packing $fileName") - val outFile = workDir + fileName.removeSuffix(".dtb") + "." + Helper.prop("config.dts_suffix") - check(DTC().compile(outFile, "$fileName.new")) { "fail to compile dts" } + packInternal(Helper.prop("workDir")!!, fileName) + } + + fun packInternal(workspace: String, outFileName: String) { + log.info("packInternal($workspace, $outFileName)") + Helper.setProp("workDir", workspace) + //workspace+cfg + val iniRole = Common.loadProperties(File(workspace, "workspace.ini").canonicalPath).getProperty("role") + val dtsSrc = File(workDir, File(iniRole).nameWithoutExtension + "." + Helper.prop("config.dts_suffix")).path + + val origFile = File(workDir, File(outFileName).name + ".orig").path + log.info("COPY $outFileName -> $origFile") + File(outFileName).copyTo(File(origFile), overwrite = true) + check(DTC().compile(dtsSrc, outFileName)) { "fail to compile dts" } //print summary val prints: MutableList> = mutableListOf() - prints.add(Pair("DTS", outFile)) - prints.add(Pair("updated DTB", "$fileName.new")) - log.info("\n\t\t\tPack Summary of {}\n{}\n", fileName, Common.table2String(prints)) + prints.add(Pair("DTS", dtsSrc)) + prints.add(Pair("updated DTB", outFileName)) + log.info("\n\t\t\tPack Summary of {}\n{}\n", outFileName, Common.table2String(prints)) } fun pull(fileName: String) { diff --git a/bbootimg/src/main/kotlin/packable/VBMetaParser.kt b/bbootimg/src/main/kotlin/packable/VBMetaParser.kt index 76a75b9..92ce4da 100644 --- a/bbootimg/src/main/kotlin/packable/VBMetaParser.kt +++ b/bbootimg/src/main/kotlin/packable/VBMetaParser.kt @@ -53,8 +53,9 @@ class VBMetaParser : IPackable { it.mkdirs() } } + //workspace.ini log.info("workspace set to $unpackDir") - Common.createWorkspaceIni(fileName) + Common.createWorkspaceIni(fileName, prefix = "vbmeta") val ai = AVBInfo.parseFrom(Dumpling(fileName)).dumpDefault(fileName) log.info("Signing Key: " + Avb.inspectKey(ai)) @@ -66,9 +67,9 @@ class VBMetaParser : IPackable { // called via reflection fun packInternal(workspace: String, outFileName: String) { - log.info("packInternal(workspace: $workspace)") + log.info("packInternal(workspace: $workspace, $outFileName)") Helper.setProp("workDir", workspace) - val iniRole = Common.loadProperties(File(workspace, "workspace.ini").canonicalPath).getProperty("role") + val iniRole = Common.loadProperties(File(workspace, "workspace.ini").canonicalPath).getProperty("vbmeta.role") val blob = ObjectMapper().readValue(File(Avb.getJsonFileName(iniRole)), AVBInfo::class.java).encodePadded() log.info("Writing padded vbmeta to file: $outFileName.signed") Files.write(Paths.get("$outFileName.signed"), blob, StandardOpenOption.CREATE) diff --git a/bbootimg/src/main/kotlin/packable/VendorBootParser.kt b/bbootimg/src/main/kotlin/packable/VendorBootParser.kt index 30b37e0..5779686 100644 --- a/bbootimg/src/main/kotlin/packable/VendorBootParser.kt +++ b/bbootimg/src/main/kotlin/packable/VendorBootParser.kt @@ -36,6 +36,7 @@ class VendorBootParser : IPackable { } fun unpackInternal(fileName: String, unpackDir: String) { + //set workdir log.info("unpackInternal(fileName: $fileName, unpackDir: $unpackDir)") Helper.setProp("workDir", unpackDir) clear() diff --git a/bbootimg/src/main/kotlin/rom/sparse/SparseImage.kt b/bbootimg/src/main/kotlin/rom/sparse/SparseImage.kt index b0917ee..c3ae20c 100644 --- a/bbootimg/src/main/kotlin/rom/sparse/SparseImage.kt +++ b/bbootimg/src/main/kotlin/rom/sparse/SparseImage.kt @@ -147,29 +147,32 @@ data class SparseImage(var info: SparseInfo = SparseInfo()) { val ret = SparseImage() ret.info.json = File(fileName).name.removeSuffix(".img") + ".json" ret.info.output = fileName - ret.info.pulp = workDir + fileName + ret.info.pulp = File(Helper.prop("workDir")!!, File(fileName).nameWithoutExtension).path + log.info(ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(ret.info)) if (isSparse(fileName)) { val tempFile = UUID.randomUUID().toString() ret.info.outerFsType = "sparse" - val rawFile = "${workDir}${File(fileName).nameWithoutExtension}" simg2img(fileName, tempFile) ret.info.pulp = if (isExt4(tempFile)) { ret.info.innerFsType = "ext4" - "$rawFile.ext4" + ret.info.pulp + ".ext4" } else if (isErofs(tempFile)) { ret.info.innerFsType = "erofs" - "$rawFile.erofs" + ret.info.pulp + ".erofs" } else { - "$rawFile.raw" + ret.info.pulp + ".raw" } Files.move(Path(tempFile), Path(ret.info.pulp)) } else if (isExt4(fileName)) { ret.info.outerFsType = "ext4" ret.info.innerFsType = "ext4" + ret.info.pulp = ret.info.pulp + ".ext4" + log.info("COPY $fileName -> ${ret.info.pulp}") File(fileName).copyTo(File(ret.info.pulp)) } else if (isErofs(fileName)) { ret.info.outerFsType = "erofs" ret.info.innerFsType = "erofs" + ret.info.pulp = ret.info.pulp + ".erofs" File(fileName).copyTo(File(ret.info.pulp)) } when (ret.info.innerFsType) { diff --git a/bbootimg/src/main/kotlin/rom/sparse/SparseImgParser.kt b/bbootimg/src/main/kotlin/rom/sparse/SparseImgParser.kt index 492f4d1..36b5dee 100644 --- a/bbootimg/src/main/kotlin/rom/sparse/SparseImgParser.kt +++ b/bbootimg/src/main/kotlin/rom/sparse/SparseImgParser.kt @@ -15,6 +15,7 @@ package rom.sparse import avb.blob.Footer +import cfig.bootimg.Common import cfig.helper.Helper import cfig.packable.IPackable import cfig.packable.VBMetaParser @@ -38,12 +39,24 @@ class SparseImgParser : IPackable { } override fun unpack(fileName: String) { + log.info("unpack(fileName: $fileName)") + unpackInternal(fileName, Helper.prop("workDir")!!) + } + + fun unpackInternal(fileName: String, unpackDir: String) { + //set workdir + log.info("unpackInternal(fileName: $fileName, unpackDir: $unpackDir)") + Helper.setProp("workDir", unpackDir) clear() + //create workspace file + Common.createWorkspaceIni(fileName) + //create workspace file done SparseImage .parse(fileName) .printSummary(fileName) } + override fun pack(fileName: String) { //TODO("not implemented: refer to https://github.com/cfig/Android_boot_image_editor/issues/133") val cfgFile = outDir + fileName.removeSuffix(".img") + ".json" @@ -54,6 +67,24 @@ class SparseImgParser : IPackable { .unwrap() } + fun packInternal(workspace: String, outFileName: String) { + log.info("packInternal($workspace, $outFileName)") + Helper.setProp("workDir", workspace) + //intermediate + Helper.joinPath(workspace, "intermediate").also { intermediateDir -> + File(intermediateDir).let { + if (!it.exists()) { + it.mkdir() + } + } + Helper.setProp("intermediateDir", intermediateDir) + } + //workspace+cfg + val iniRole = Common.loadProperties(File(workspace, "workspace.ini").canonicalPath).getProperty("role") + val cfgFile = File(workspace, iniRole.removeSuffix(".img") + ".json").canonicalPath + log.info("Loading config from $cfgFile") + } + // invoked solely by reflection fun `@footer`(fileName: String) { FileInputStream(fileName).use { fis ->