Issue #117: respect original check flags for ramdisk compression

ramdisk xz check flags: crc32/crc64 etc.
XiaoMi recovery image uses CRC32 and can not suppport CRC64
pull/140/head
cfig 2 years ago
parent d0dfebd42e
commit 2f0af5d259
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

@ -258,7 +258,7 @@ class Common {
} }
//using preset fs_config //using preset fs_config
fun packRootfs(rootDir: String, ramdiskGz: String) { fun packRootfs(rootDir: String, ramdiskGz: String, compressorArgs: String? = null) {
val root = File(rootDir).path val root = File(rootDir).path
log.info("Packing rootfs $root ...") log.info("Packing rootfs $root ...")
when { when {
@ -280,7 +280,7 @@ class Common {
ramdiskGz.endsWith(".xz") -> { ramdiskGz.endsWith(".xz") -> {
val f = ramdiskGz.removeSuffix(".xz") val f = ramdiskGz.removeSuffix(".xz")
AndroidCpio().pack(root, f, "${f}_filelist.txt") AndroidCpio().pack(root, f, "${f}_filelist.txt")
FileInputStream(f).use { ZipHelper.xz(ramdiskGz, it) } FileInputStream(f).use { ZipHelper.xz(ramdiskGz, it, compressorArgs!!) }
} }
ramdiskGz.endsWith(".cpio") -> { ramdiskGz.endsWith(".cpio") -> {
val f = ramdiskGz.removeSuffix(".cpio") val f = ramdiskGz.removeSuffix(".cpio")

@ -16,11 +16,13 @@ package cfig.bootimg.v2
import avb.AVBInfo import avb.AVBInfo
import cfig.Avb import cfig.Avb
import cfig.bootimg.Common as C
import cfig.bootimg.Common import cfig.bootimg.Common
import cfig.bootimg.Common.Companion.deleleIfExists import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Signer import cfig.bootimg.Signer
import cfig.helper.Dumpling import cfig.helper.Dumpling
import cfig.helper.Helper import cfig.helper.Helper
import cfig.helper.ZipHelper
import cfig.packable.VBMetaParser import cfig.packable.VBMetaParser
import cfig.utils.DTC import cfig.utils.DTC
import cfig.utils.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
@ -39,7 +41,7 @@ import java.nio.ByteOrder
data class BootV2( data class BootV2(
var info: MiscInfo = MiscInfo(), var info: MiscInfo = MiscInfo(),
var kernel: CommArgs = CommArgs(), var kernel: CommArgs = CommArgs(),
var ramdisk: CommArgs = CommArgs(), var ramdisk: RamdiskArgs = RamdiskArgs(),
var secondBootloader: CommArgs? = null, var secondBootloader: CommArgs? = null,
var recoveryDtbo: CommArgsLong? = null, var recoveryDtbo: CommArgsLong? = null,
var dtb: CommArgsLong? = null, var dtb: CommArgsLong? = null,
@ -68,6 +70,14 @@ data class BootV2(
var loadOffset: Long = 0, var loadOffset: Long = 0,
) )
data class RamdiskArgs(
var file: String? = null,
var position: Long = 0,
var size: Int = 0,
var loadOffset: Long = 0,
var xzFlags: String? = null
)
data class CommArgsLong( data class CommArgsLong(
var file: String? = null, var file: String? = null,
var position: Long = 0, var position: Long = 0,
@ -193,10 +203,14 @@ data class BootV2(
Common.dumpKernel(Helper.Slice(info.output, kernel.position.toInt(), kernel.size, kernel.file!!)) Common.dumpKernel(Helper.Slice(info.output, kernel.position.toInt(), kernel.size, kernel.file!!))
//ramdisk //ramdisk
if (this.ramdisk.size > 0) { if (this.ramdisk.size > 0) {
val fmt = Common.dumpRamdisk( val fmt = C.dumpRamdisk(
Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file!!), "${workDir}root" Helper.Slice(info.output, ramdisk.position.toInt(), ramdisk.size, ramdisk.file!!), "${workDir}root"
) )
this.ramdisk.file = this.ramdisk.file!! + ".$fmt" this.ramdisk.file = this.ramdisk.file!! + ".$fmt"
if (fmt == "xz") {
val checkType = ZipHelper.xzStreamFlagCheckTypeToString(ZipHelper.parseStreamFlagCheckType(this.ramdisk.file!!))
this.ramdisk.xzFlags = checkType
}
//dump info again //dump info again
mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + this.info.json), this) mapper.writerWithDefaultPrettyPrinter().writeValue(File(workDir + this.info.json), this)
} }
@ -398,7 +412,7 @@ data class BootV2(
File(this.ramdisk.file!!).deleleIfExists() File(this.ramdisk.file!!).deleleIfExists()
File(this.ramdisk.file!!.removeSuffix(".gz")).deleleIfExists() File(this.ramdisk.file!!.removeSuffix(".gz")).deleleIfExists()
//Common.packRootfs("${workDir}/root", this.ramdisk.file!!, Common.parseOsMajor(info.osVersion.toString())) //Common.packRootfs("${workDir}/root", this.ramdisk.file!!, Common.parseOsMajor(info.osVersion.toString()))
Common.packRootfs("${workDir}/root", this.ramdisk.file!!) Common.packRootfs("${workDir}/root", this.ramdisk.file!!, this.ramdisk.xzFlags)
} }
this.ramdisk.size = File(this.ramdisk.file!!).length().toInt() this.ramdisk.size = File(this.ramdisk.file!!).length().toInt()
} }

@ -37,7 +37,7 @@ import java.nio.ByteOrder
data class BootV2Dialects( data class BootV2Dialects(
var info: MiscInfo = MiscInfo(), var info: MiscInfo = MiscInfo(),
var kernel: CommArgs = CommArgs(), var kernel: CommArgs = CommArgs(),
var ramdisk: CommArgs = CommArgs(), var ramdisk: BootV2.RamdiskArgs = BootV2.RamdiskArgs(),
var secondBootloader: CommArgs? = null, var secondBootloader: CommArgs? = null,
var recoveryDtbo: CommArgsLong? = null, var recoveryDtbo: CommArgsLong? = null,
var dtb: CommArgsLong? = null, var dtb: CommArgsLong? = null,
@ -378,7 +378,7 @@ data class BootV2Dialects(
File(this.ramdisk.file!!).deleleIfExists() File(this.ramdisk.file!!).deleleIfExists()
File(this.ramdisk.file!!.removeSuffix(".gz")).deleleIfExists() File(this.ramdisk.file!!.removeSuffix(".gz")).deleleIfExists()
//Common.packRootfs("${workDir}/root", this.ramdisk.file!!, Common.parseOsMajor(info.osVersion.toString())) //Common.packRootfs("${workDir}/root", this.ramdisk.file!!, Common.parseOsMajor(info.osVersion.toString()))
Common.packRootfs("${workDir}/root", this.ramdisk.file!!) Common.packRootfs("${workDir}/root", this.ramdisk.file!!, this.ramdisk.xzFlags)
} }
this.ramdisk.size = File(this.ramdisk.file!!).length().toInt() this.ramdisk.size = File(this.ramdisk.file!!).length().toInt()
} }

@ -25,6 +25,7 @@ import cfig.bootimg.Common.Companion.getPaddingSize
import cfig.bootimg.Signer import cfig.bootimg.Signer
import cfig.helper.Helper import cfig.helper.Helper
import cfig.helper.Dumpling import cfig.helper.Dumpling
import cfig.helper.ZipHelper
import cfig.packable.VBMetaParser import cfig.packable.VBMetaParser
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import de.vandermeer.asciitable.AsciiTable import de.vandermeer.asciitable.AsciiTable
@ -41,7 +42,7 @@ import cfig.bootimg.Common as C
data class BootV3( data class BootV3(
var info: MiscInfo = MiscInfo(), var info: MiscInfo = MiscInfo(),
var kernel: CommArgs = CommArgs(), var kernel: CommArgs = CommArgs(),
val ramdisk: CommArgs = CommArgs(), val ramdisk: RamdiskArgs = RamdiskArgs(),
var bootSignature: CommArgs = CommArgs(), var bootSignature: CommArgs = CommArgs(),
) { ) {
companion object { companion object {
@ -105,6 +106,13 @@ data class BootV3(
var size: Int = 0, var size: Int = 0,
) )
data class RamdiskArgs (
var file: String = "",
var position: Int = 0,
var size: Int = 0,
var xzFlags: String? = null
)
fun pack(): BootV3 { fun pack(): BootV3 {
if (this.kernel.size > 0) { if (this.kernel.size > 0) {
this.kernel.size = File(this.kernel.file).length().toInt() this.kernel.size = File(this.kernel.file).length().toInt()
@ -119,7 +127,7 @@ data class BootV3(
//TODO: remove cpio in C/C++ //TODO: remove cpio in C/C++
//C.packRootfs("$workDir/root", this.ramdisk.file, C.parseOsMajor(info.osVersion)) //C.packRootfs("$workDir/root", this.ramdisk.file, C.parseOsMajor(info.osVersion))
// enable advance JAVA cpio // enable advance JAVA cpio
C.packRootfs("$workDir/root", this.ramdisk.file) C.packRootfs("$workDir/root", this.ramdisk.file, this.ramdisk.xzFlags)
} }
this.ramdisk.size = File(this.ramdisk.file).length().toInt() this.ramdisk.size = File(this.ramdisk.file).length().toInt()
} }
@ -232,6 +240,10 @@ data class BootV3(
Helper.Slice(info.output, ramdisk.position, ramdisk.size, ramdisk.file), "${workDir}root" Helper.Slice(info.output, ramdisk.position, ramdisk.size, ramdisk.file), "${workDir}root"
) )
this.ramdisk.file = this.ramdisk.file + ".$fmt" this.ramdisk.file = this.ramdisk.file + ".$fmt"
if (fmt == "xz") {
val checkType = ZipHelper.xzStreamFlagCheckTypeToString(ZipHelper.parseStreamFlagCheckType(this.ramdisk.file))
this.ramdisk.xzFlags = checkType
}
} }
//bootsig //bootsig

@ -22,6 +22,7 @@ import cfig.bootimg.Common.Companion.deleleIfExists
import cfig.bootimg.Signer import cfig.bootimg.Signer
import cfig.helper.Dumpling import cfig.helper.Dumpling
import cfig.helper.Helper import cfig.helper.Helper
import cfig.helper.ZipHelper
import cfig.packable.VBMetaParser import cfig.packable.VBMetaParser
import cfig.utils.DTC import cfig.utils.DTC
import cfig.utils.EnvironmentVerifier import cfig.utils.EnvironmentVerifier
@ -37,7 +38,7 @@ import cfig.bootimg.Common as C
data class VendorBoot( data class VendorBoot(
var info: MiscInfo = MiscInfo(), var info: MiscInfo = MiscInfo(),
var ramdisk: CommArgs = CommArgs(), var ramdisk: RamdiskArgs = RamdiskArgs(),
var dtb: CommArgs = CommArgs(), var dtb: CommArgs = CommArgs(),
var ramdisk_table: Vrt = Vrt(), var ramdisk_table: Vrt = Vrt(),
var bootconfig: CommArgs = CommArgs(), var bootconfig: CommArgs = CommArgs(),
@ -49,6 +50,14 @@ data class VendorBoot(
var loadAddr: Long = 0, var loadAddr: Long = 0,
) )
data class RamdiskArgs(
var file: String = "",
var position: Long = 0,
var size: Int = 0,
var loadAddr: Long = 0,
var xzFlags: String? = null
)
data class MiscInfo( data class MiscInfo(
var output: String = "", var output: String = "",
var json: String = "", var json: String = "",
@ -227,7 +236,7 @@ data class VendorBoot(
//Fixed: remove cpio in C/C++ //Fixed: remove cpio in C/C++
//C.packRootfs("$workDir/root", this.ramdisk.file, parseOsMajor()) //C.packRootfs("$workDir/root", this.ramdisk.file, parseOsMajor())
//enable advance JAVA cpio //enable advance JAVA cpio
C.packRootfs("$workDir/root", this.ramdisk.file) C.packRootfs("$workDir/root", this.ramdisk.file, this.ramdisk.xzFlags)
} }
this.ramdisk.size = File(this.ramdisk.file).length().toInt() this.ramdisk.size = File(this.ramdisk.file).length().toInt()
} }
@ -235,7 +244,7 @@ data class VendorBoot(
this.ramdisk_table.ramdidks.forEachIndexed { index, it -> this.ramdisk_table.ramdidks.forEachIndexed { index, it ->
File(it.file).deleleIfExists() File(it.file).deleleIfExists()
log.info(workDir + "root.${index + 1} -> " + it.file) log.info(workDir + "root.${index + 1} -> " + it.file)
C.packRootfs(workDir + "root.${index + 1}", it.file) C.packRootfs(workDir + "root.${index + 1}", it.file, this.ramdisk.xzFlags)
} }
this.ramdisk.size = this.ramdisk_table.ramdidks.sumOf { File(it.file).length() }.toInt() this.ramdisk.size = this.ramdisk_table.ramdidks.sumOf { File(it.file).length() }.toInt()
} }
@ -345,6 +354,10 @@ data class VendorBoot(
this.ramdisk_table.ramdidks.isEmpty()) this.ramdisk_table.ramdidks.isEmpty())
//@formatter:on //@formatter:on
this.ramdisk.file = this.ramdisk.file + ".$fmt" this.ramdisk.file = this.ramdisk.file + ".$fmt"
if (fmt == "xz") {
val checkType = ZipHelper.xzStreamFlagCheckTypeToString(ZipHelper.parseStreamFlagCheckType(this.ramdisk.file))
this.ramdisk.xzFlags = checkType
}
//dtb //dtb
C.dumpDtb(Helper.Slice(info.output, dtb.position.toInt(), dtb.size, dtb.file)) C.dumpDtb(Helper.Slice(info.output, dtb.position.toInt(), dtb.size, dtb.file))
//vrt //vrt

@ -69,7 +69,7 @@ class DeltaGenerator {
//try xz //try xz
File.createTempFile("pre", "suf").let { tempFile -> File.createTempFile("pre", "suf").let { tempFile ->
tempFile.deleteOnExit() tempFile.deleteOnExit()
ZipHelper.xz(tempFile.absolutePath, ByteArrayInputStream(inData)) ZipHelper.xz(tempFile.absolutePath, ByteArrayInputStream(inData), "CRC64")
log.debug("raw=${inData.size}, xz=" + tempFile.length()) log.debug("raw=${inData.size}, xz=" + tempFile.length())
if (bestSize > tempFile.length()) { if (bestSize > tempFile.length()) {
bestType = Type.REPLACE_XZ bestType = Type.REPLACE_XZ

@ -17,11 +17,8 @@ package cfig.helper
import cc.cfig.io.Struct import cc.cfig.io.Struct
import cfig.helper.Helper.Companion.check_call import cfig.helper.Helper.Companion.check_call
import cfig.helper.Helper.Companion.check_output import cfig.helper.Helper.Companion.check_output
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry import org.apache.commons.compress.archivers.zip.*
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream import org.apache.commons.compress.compressors.CompressorOutputStream
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream
import org.apache.commons.compress.archivers.zip.ZipFile
import org.apache.commons.compress.archivers.zip.ZipMethod
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream
@ -34,9 +31,10 @@ import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor
import org.apache.commons.exec.PumpStreamHandler import org.apache.commons.exec.PumpStreamHandler
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.tukaani.xz.LZMA2Options
import org.tukaani.xz.XZFormatException import org.tukaani.xz.XZFormatException
import org.tukaani.xz.XZOutputStream
import java.io.* import java.io.*
import java.lang.RuntimeException
import java.net.URI import java.net.URI
import java.nio.file.FileSystems import java.nio.file.FileSystems
import java.nio.file.Files import java.nio.file.Files
@ -50,6 +48,43 @@ import kotlin.reflect.jvm.isAccessible
class ZipHelper { class ZipHelper {
class ZipEntryRecipe(val data: ByteArray, val name: String, val method: ZipMethod) class ZipEntryRecipe(val data: ByteArray, val name: String, val method: ZipMethod)
class XZCompressorOutputStream2 : CompressorOutputStream {
private val out: XZOutputStream
constructor(outputStream: OutputStream?) {
out = XZOutputStream(outputStream, LZMA2Options())
}
constructor(outputStream: OutputStream?, checkType: Int) {
out = XZOutputStream(outputStream, LZMA2Options(), checkType)
}
@Throws(IOException::class)
override fun write(b: Int) {
out.write(b)
}
@Throws(IOException::class)
override fun write(buf: ByteArray, off: Int, len: Int) {
out.write(buf, off, len)
}
@Throws(IOException::class)
override fun flush() {
out.flush()
}
@Throws(IOException::class)
fun finish() {
out.finish()
}
@Throws(IOException::class)
override fun close() {
out.close()
}
}
companion object { companion object {
private val log = LoggerFactory.getLogger("ZipHelper") private val log = LoggerFactory.getLogger("ZipHelper")
@ -86,9 +121,11 @@ class ZipHelper {
entryOut.mkdir() entryOut.mkdir()
log.debug("Unzipping[d]: ${entry.name}") log.debug("Unzipping[d]: ${entry.name}")
} }
entry.isUnixSymlink -> { entry.isUnixSymlink -> {
throw IllegalArgumentException("this should not happen: Found dir ${entry.name}") throw IllegalArgumentException("this should not happen: Found dir ${entry.name}")
} }
else -> { else -> {
val entryOut = File(outDir + "/" + entry.name) val entryOut = File(outDir + "/" + entry.name)
log.debug("Unzipping[f]: ${entry.name}") log.debug("Unzipping[f]: ${entry.name}")
@ -282,6 +319,54 @@ class ZipHelper {
log.info("decompress(lzma) done: $compressedFile -> $decompressedFile") log.info("decompress(lzma) done: $compressedFile -> $decompressedFile")
} }
// https://tukaani.org/xz/xz-file-format.txt
// 2.1.1. Stream Header
fun parseStreamFlagCheckType(file: String): Int {
FileInputStream(file).use { fis ->
val ba = ByteArray(6)
check(fis.read(ba) == ba.size)
check(ba.contentEquals(byteArrayOf(0xfd.toByte(), 0x37, 0x7a, 0x58, 0x5a, 0x00))) {
log.warn("wrong magic bytes in xz header")
}
check(fis.read(ba) == ba.size)
check(ba[0] == 0x00.toByte())
when (ba[1].toInt()) {
0x00 -> log.info("NONE")
0x01 -> log.info("CRC32")
0x04 -> log.info("CRC64")
0x0a -> log.info("SHA256")
else -> throw IllegalArgumentException(
"unsupported StreamFlag.CheckType: 0x" + ba[1].toInt().toString(16)
)
}
return ba[1].toInt()
}
}
fun xzStreamFlagCheckTypeToString(type: Int): String {
return when (type) {
0x00 -> "NONE"
0x01 -> "CRC32"
0x04 -> "CRC64"
0x0a -> "SHA256"
else -> throw IllegalArgumentException(
"unsupported StreamFlag.CheckType: 0x" + type.toString(16)
)
}
}
fun xzStreamFlagCheckTypeFromString(typeStr: String): Int {
return when (typeStr) {
"NONE" -> 0x00
"CRC32" -> 0x01
"CRC64" -> 0x04
"SHA256" -> 0x0a
else -> throw IllegalArgumentException(
"unsupported StreamFlag.CheckType: 0x$typeStr"
)
}
}
fun isXz(compressedFile: String): Boolean { fun isXz(compressedFile: String): Boolean {
return try { return try {
FileInputStream(compressedFile).use { fis -> FileInputStream(compressedFile).use { fis ->
@ -294,10 +379,10 @@ class ZipHelper {
} }
} }
fun xz(compressedFile: String, fis: InputStream) { fun xz(compressedFile: String, fis: InputStream, checkType: String) {
log.info("Compress(xz) ... ") log.info("Compress(xz), with checkType $checkType... ")
FileOutputStream(compressedFile).use { fos -> FileOutputStream(compressedFile).use { fos ->
XZCompressorOutputStream(fos).use { gos -> XZCompressorOutputStream2(fos, ZipHelper.xzStreamFlagCheckTypeFromString(checkType)).use { gos ->
val buffer = ByteArray(1024) val buffer = ByteArray(1024)
while (true) { while (true) {
val bytesRead = fis.read(buffer) val bytesRead = fis.read(buffer)

@ -176,6 +176,8 @@ def main():
verifySingleDir(resDir2, "issue_91_unsigned_vendor_boot") verifySingleDir(resDir2, "issue_91_unsigned_vendor_boot")
# Issue 109: vendor_boot w/o dtb # Issue 109: vendor_boot w/o dtb
verifySingleDir(resDir2, "issue_109_vendor_boot_no_dtb") verifySingleDir(resDir2, "issue_109_vendor_boot_no_dtb")
# Issue 117: xz crc32/crc64
verifySingleDir(resDir2, "issue_117_xz_crc")
log.info(successLogo) log.info(successLogo)

@ -1 +1 @@
Subproject commit 0caca0031646be47eb89ae1e4380a524f63ec52b Subproject commit bf9b8b996723536fcc19768185d87272f5363f76
Loading…
Cancel
Save