From 227bc44a7543872a6f66e07a081cd04b0474a64a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 28 Aug 2023 03:13:58 +0200 Subject: [PATCH] Improvements --- Ffu2Vhdx/Program.cs | 93 ++++++++++++++++++--- FfuStream/FfuFile.cs | 2 +- FfuStream/FfuStoreStream.cs | 4 +- ImageCommon/FullFlashUpdateStore.cs | 4 +- ImageStorageServiceManaged/PayloadReader.cs | 35 ++++++-- 5 files changed, 118 insertions(+), 20 deletions(-) diff --git a/Ffu2Vhdx/Program.cs b/Ffu2Vhdx/Program.cs index ce7a4bc..48660dc 100644 --- a/Ffu2Vhdx/Program.cs +++ b/Ffu2Vhdx/Program.cs @@ -9,6 +9,8 @@ namespace Ffu2Vhdx { static void Main(string[] args) { + Console.WriteLine("\nFFU Image To VHDx(s) tool\nVersion: 1.0.0.0\n"); + if (args.Length != 2) { Console.WriteLine("Usage: Ffu2Vhdx "); @@ -33,6 +35,69 @@ namespace Ffu2Vhdx ConvertFFU2VHD(FfuPath, OutputDirectory); } + private readonly static Guid EmmcUserPartitionGuid = new("B615F1F5-5088-43CD-809C-A16E52487D00"); + private readonly static Guid EmmcBootPartition1Guid = new("12C55B20-25D3-41C9-8E06-282D94C676AD"); + private readonly static Guid EmmcBootPartition2Guid = new("6B76A6DB-0257-48A9-AA99-F6B1655F7B00"); + private readonly static Guid EmmcRpmbPartitionGuid = new("C49551EA-D6BC-4966-9499-871E393133CD"); + private readonly static Guid EmmcGppPartition1Guid = new("B9251EA5-3462-4807-86C6-8948B1B36163"); + private readonly static Guid EmmcGppPartition2Guid = new("24F906CD-EE11-43E1-8427-DC7A36F4C059"); + private readonly static Guid EmmcGppPartition3Guid = new("5A5709A9-AC40-4F72-8862-5B0104166E76"); + private readonly static Guid EmmcGppPartition4Guid = new("A44E27C9-258E-406E-BF33-77F5F244C487"); + private readonly static Guid SdRemovableGuid = new("D1531D41-3F80-4091-8D0A-541F59236D66"); + private readonly static Guid UfsLU0Guid = new("860845C1-BE09-4355-8BC1-30D64FF8E63A"); + private readonly static Guid UfsLU1Guid = new("8D90D477-39A3-4A38-AB9E-586FF69ED051"); + private readonly static Guid UfsLU2Guid = new("EDF85868-87EC-4F77-9CDA-5F10DF2FE601"); + private readonly static Guid UfsLU3Guid = new("1AE69024-8AEB-4DF8-BC98-0032DBDF5024"); + private readonly static Guid UfsLU4Guid = new("D33F1985-F107-4A85-BE38-68DC7AD32CEA"); + private readonly static Guid UfsLU5Guid = new("4BA1D05F-088E-483F-A97E-B19B9CCF59B0"); + private readonly static Guid UfsLU6Guid = new("4ACF98F6-26FA-44D2-8132-282F2D19A4C5"); + private readonly static Guid UfsLU7Guid = new("8598155F-34DE-415C-8B55-843E3322D36F"); + private readonly static Guid UfsRPMBGuid = new("5397474E-F75D-44B3-8E57-D9324FCF6FE1"); + + private static Dictionary guidNames = new Dictionary() + { + { EmmcUserPartitionGuid, "eMMC (User)" }, + { EmmcBootPartition1Guid, "eMMC (Boot 1)" }, + { EmmcBootPartition2Guid, "eMMC (Boot 2)" }, + { EmmcRpmbPartitionGuid, "eMMC (RPMB)" }, + { EmmcGppPartition1Guid, "eMMC (GPP 1)" }, + { EmmcGppPartition2Guid, "eMMC (GPP 2)" }, + { EmmcGppPartition3Guid, "eMMC (GPP 3)" }, + { EmmcGppPartition4Guid, "eMMC (GPP 4)" }, + { SdRemovableGuid, "SD Card (Removable)" }, + { UfsLU0Guid, "UFS (LUN 0)" }, + { UfsLU1Guid, "UFS (LUN 1)" }, + { UfsLU2Guid, "UFS (LUN 2)" }, + { UfsLU3Guid, "UFS (LUN 3)" }, + { UfsLU4Guid, "UFS (LUN 4)" }, + { UfsLU5Guid, "UFS (LUN 5)" }, + { UfsLU6Guid, "UFS (LUN 6)" }, + { UfsLU7Guid, "UFS (LUN 7)" }, + { UfsRPMBGuid, "UFS (RPMB)" }, + }; + + private static string FormatDevicePath(string DevicePath) + { + if (DevicePath.Contains("VenHw(")) + { + string DevicePathGuidBit = DevicePath.Split("(")[^1].Split(")")[0]; + if (Guid.TryParse(DevicePathGuidBit, out Guid DevicePathGuid)) + { + if (guidNames.TryGetValue(DevicePathGuid, out string FriendlyDesc)) + { + return $"{DevicePath}: {FriendlyDesc}"; + } + } + } + + return DevicePath; + } + + private static string ReplaceInvalidChars(string filename) + { + return string.Join("_", filename.Split(Path.GetInvalidFileNameChars())); + } + private static void ConvertFFU2VHD(string ffuPath, string outputDirectory) { DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(Disk).Assembly); @@ -42,22 +107,28 @@ namespace Ffu2Vhdx for (int i = 0; i < ffuFile.StoreCount; i++) { - string vhdfile = Path.Combine(outputDirectory, $"LUN{i}.vhdx"); - Console.WriteLine($"Dumping {vhdfile}..."); + using FfuStoreStream store = ffuFile.OpenStore(i); + + string friendlyDevicePath = FormatDevicePath(store.DevicePath); + string vhdfile = Path.Combine(outputDirectory, $"Store{i}_{ReplaceInvalidChars(store.DevicePath)}.vhdx"); + + Console.WriteLine($"Store: {i}"); + Console.WriteLine($"Size: {store.Length}"); + Console.WriteLine($"Device Path: {friendlyDevicePath}"); + Console.WriteLine($"Destination: {vhdfile}"); + + long SectorSize = ffuFile.GetSectorSize(i); - long diskCapacity = (long)ffuFile.GetMinSectorCount(i) * ffuFile.GetSectorSize(i); using Stream fs = new FileStream(vhdfile, FileMode.CreateNew, FileAccess.ReadWrite); - using VirtualDisk outDisk = Disk.InitializeDynamic(fs, Ownership.None, diskCapacity, logicalSectorSize: (int)ffuFile.GetSectorSize(i)); - - using Stream store = ffuFile.OpenStore(i); + using VirtualDisk outDisk = Disk.InitializeDynamic(fs, Ownership.None, store.Length, logicalSectorSize: (int)SectorSize); StreamPump pump = new() { InputStream = store, OutputStream = outDisk.Content, SparseCopy = true, - SparseChunkSize = (int)ffuFile.GetSectorSize(i), - BufferSize = (int)ffuFile.GetSectorSize(i) * 1024 + SparseChunkSize = (int)SectorSize, + BufferSize = (int)SectorSize * 1024 }; long totalBytes = store.Length; @@ -67,10 +138,10 @@ namespace Ffu2Vhdx Console.WriteLine($"Dumping Store {i}"); pump.Run(); - Console.WriteLine(); - - store.Dispose(); + Console.WriteLine("\n"); } + + Console.WriteLine("The operation completed successfully."); } protected static void ShowProgress(ulong readBytes, ulong totalBytes, DateTime startTime) diff --git a/FfuStream/FfuFile.cs b/FfuStream/FfuFile.cs index 0d141f6..afea06f 100644 --- a/FfuStream/FfuFile.cs +++ b/FfuStream/FfuFile.cs @@ -35,7 +35,7 @@ namespace FfuStream payloadReader.WriteToStream(outputStream, storePayload, fullFlashUpdateStore.MinSectorCount, fullFlashUpdateStore.SectorSize); } - public Stream OpenStore(int StoreIndex) + public FfuStoreStream OpenStore(int StoreIndex) { if (StoreIndex >= StoreCount || StoreIndex < 0) { diff --git a/FfuStream/FfuStoreStream.cs b/FfuStream/FfuStoreStream.cs index 4e83fb0..f75335c 100644 --- a/FfuStream/FfuStoreStream.cs +++ b/FfuStream/FfuStoreStream.cs @@ -16,13 +16,15 @@ namespace FfuStream this.storePayload = storePayload; } + public string DevicePath => fullFlashUpdateStore.DevicePath; + public override bool CanRead => true; public override bool CanSeek => true; public override bool CanWrite => false; - public override long Length => fullFlashUpdateStore.MinSectorCount * fullFlashUpdateStore.SectorSize; + public override long Length => ((long)fullFlashUpdateStore.MinSectorCount * fullFlashUpdateStore.SectorSize); public override long Position { diff --git a/ImageCommon/FullFlashUpdateStore.cs b/ImageCommon/FullFlashUpdateStore.cs index 313f428..cb57927 100644 --- a/ImageCommon/FullFlashUpdateStore.cs +++ b/ImageCommon/FullFlashUpdateStore.cs @@ -84,9 +84,9 @@ namespace Microsoft.WindowsPhone.Imaging get; set; } - private string DevicePath + public string DevicePath { - get; set; + get; private set; } private bool OnlyAllocateDefinedGptEntries diff --git a/ImageStorageServiceManaged/PayloadReader.cs b/ImageStorageServiceManaged/PayloadReader.cs index 68ff52d..16affb1 100644 --- a/ImageStorageServiceManaged/PayloadReader.cs +++ b/ImageStorageServiceManaged/PayloadReader.cs @@ -92,7 +92,7 @@ namespace Microsoft.WindowsPhone.Imaging return end > begin; } - private static void WriteDetour(long inputPosition, byte[] inputBuffer, int inputCount, long position, byte[] buffer, int offset, int count) + private static int WriteDetour(long inputPosition, byte[] inputBuffer, int inputCount, long position, byte[] buffer, int offset, int count) { long begin = Math.Max(inputPosition, position); long end = Math.Min(inputPosition + inputCount, position + count); @@ -105,7 +105,11 @@ namespace Microsoft.WindowsPhone.Imaging using var strm = new MemoryStream(buffer); strm.Seek(index, SeekOrigin.Begin); strm.Write(inputBuffer, inputIndex, (int)(end - begin)); + + return (int)(end - begin); } + + return 0; } public void WriteToStream(StorePayload storePayload, ulong sectorCount, uint sectorSize, long position, byte[] buffer, int offset, int count) @@ -121,10 +125,20 @@ namespace Microsoft.WindowsPhone.Imaging _payloadStream.Position = payloadOffset.Offset; + int blocksRead = 0; + for (StorePayload.BlockPhase blockPhase = StorePayload.BlockPhase.Phase1; blockPhase != StorePayload.BlockPhase.Invalid; blockPhase++) { + int readCount = 0; + foreach (DataBlockEntry dataBlockEntry in storePayload.GetPhaseEntries(blockPhase)) { + if (readCount == count) + { + blocksRead++; + continue; + } + bool blockMatches = false; byte[] ibuffer = new byte[bytesPerBlock]; @@ -138,22 +152,33 @@ namespace Microsoft.WindowsPhone.Imaging if (blockMatches) { - WriteDetour(ioffset, ibuffer, (int)bytesPerBlock, position, buffer, offset, count); + readCount += WriteDetour(ioffset, ibuffer, (int)bytesPerBlock, position, buffer, offset, count); + if (readCount == count) + { + break; + } } else { blockMatches = WriteDetourOk(ioffset, (int)bytesPerBlock, position, count); if (blockMatches) { + _payloadStream.Position = payloadOffset.Offset + (bytesPerBlock * blocksRead); _payloadStream.Read(ibuffer, 0, (int)bytesPerBlock); - WriteDetour(ioffset, ibuffer, (int)bytesPerBlock, position, buffer, offset, count); + blocksRead++; + + readCount += WriteDetour(ioffset, ibuffer, (int)bytesPerBlock, position, buffer, offset, count); + if (readCount == count) + { + break; + } } } } if (!blockMatches) { - _payloadStream.Seek((int)bytesPerBlock, SeekOrigin.Current); + blocksRead++; } } } @@ -206,4 +231,4 @@ namespace Microsoft.WindowsPhone.Imaging } } } -} +} \ No newline at end of file