mirror of
https://github.com/MobileTooling/Ffu2Vhdx.git
synced 2026-07-27 12:48:20 -07:00
Improvements
This commit is contained in:
+82
-11
@@ -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 <Path to FFU File> <Output director for LUNi.vhdx files>");
|
||||
@@ -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<Guid, string> guidNames = new Dictionary<Guid, string>()
|
||||
{
|
||||
{ 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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -84,9 +84,9 @@ namespace Microsoft.WindowsPhone.Imaging
|
||||
get; set;
|
||||
}
|
||||
|
||||
private string DevicePath
|
||||
public string DevicePath
|
||||
{
|
||||
get; set;
|
||||
get; private set;
|
||||
}
|
||||
|
||||
private bool OnlyAllocateDefinedGptEntries
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user