|
| 1 | +using System.Drawing; |
| 2 | + |
| 3 | +namespace PartitionOffsetsHelperTool.GPT |
| 4 | +{ |
| 5 | + internal class GPTUtils |
| 6 | + { |
| 7 | + internal static void MakeGPT(ulong DiskSize, ulong SectorSize, GPTPartition[] DefaultPartitionTable, ulong AndroidDesiredSpace = 4_294_967_296) |
| 8 | + { |
| 9 | + ulong LastLBA = DiskSize / SectorSize - 1; |
| 10 | + |
| 11 | + ulong PartitionArrayLBACount = 4; |
| 12 | + ulong TotalGPTLBACount = 1 /* GPT Header */ + PartitionArrayLBACount /* Partition Table */; |
| 13 | + ulong LastUsableLBA = LastLBA - TotalGPTLBACount; |
| 14 | + |
| 15 | + List<GPTPartition> Partitions = new(DefaultPartitionTable); |
| 16 | + Partitions[^1].LastLBA = LastUsableLBA; |
| 17 | + |
| 18 | + if (AndroidDesiredSpace < 4_294_967_296) |
| 19 | + { |
| 20 | + throw new Exception("ERROR"); |
| 21 | + } |
| 22 | + |
| 23 | + InjectWindowsPartitions(Partitions, SectorSize, 4, AndroidDesiredSpace); |
| 24 | + } |
| 25 | + |
| 26 | + private static void InjectWindowsPartitions(List<GPTPartition> Partitions, ulong SectorSize, ulong BlockSize, ulong AndroidDesiredSpace) |
| 27 | + { |
| 28 | + ulong FirstUsableLBA = Partitions.Last().FirstLBA; |
| 29 | + ulong LastUsableLBA = Partitions.Last().LastLBA; |
| 30 | + |
| 31 | + if (LastUsableLBA % BlockSize != 0) |
| 32 | + { |
| 33 | + LastUsableLBA -= LastUsableLBA % BlockSize; |
| 34 | + } |
| 35 | + |
| 36 | + ulong UsableLBACount = LastUsableLBA - FirstUsableLBA + 1; |
| 37 | + |
| 38 | + ulong SixtyFourGigaBytes = 68_719_476_736 / SectorSize; |
| 39 | + |
| 40 | + ulong ESPLBACount = 65525 + 1024 + 1 /* Cluster Size Limit for FAT32 */; |
| 41 | + if (ESPLBACount % BlockSize != 0) |
| 42 | + { |
| 43 | + ESPLBACount += BlockSize - ESPLBACount % BlockSize; |
| 44 | + } |
| 45 | + |
| 46 | + /* Strategy to reserve 4GB for Android Only */ |
| 47 | + ulong FourGigaBytes = AndroidDesiredSpace / SectorSize; |
| 48 | + ulong WindowsLBACount = UsableLBACount - ESPLBACount - FourGigaBytes; |
| 49 | + |
| 50 | + if (WindowsLBACount < SixtyFourGigaBytes) |
| 51 | + { |
| 52 | + WindowsLBACount = SixtyFourGigaBytes; |
| 53 | + } |
| 54 | + |
| 55 | + if (WindowsLBACount % BlockSize != 0) |
| 56 | + { |
| 57 | + WindowsLBACount -= WindowsLBACount % BlockSize; |
| 58 | + } |
| 59 | + |
| 60 | + ulong TotalInjectedLBACount = ESPLBACount + WindowsLBACount; |
| 61 | + |
| 62 | + ulong ESPFirstLBA = LastUsableLBA - TotalInjectedLBACount; |
| 63 | + ulong ESPLastLBA = ESPFirstLBA + ESPLBACount - 1; |
| 64 | + |
| 65 | + ulong WindowsFirstLBA = ESPLastLBA + 1; |
| 66 | + ulong WindowsLastLBA = ESPLastLBA + WindowsLBACount; |
| 67 | + |
| 68 | + if (ESPFirstLBA % BlockSize != 0) |
| 69 | + { |
| 70 | + ulong Padding = BlockSize - ESPFirstLBA % BlockSize; |
| 71 | + throw new Exception("ESPFirstLBA overflew block alignment by: " + Padding); |
| 72 | + } |
| 73 | + |
| 74 | + if ((ESPLastLBA + 1) % BlockSize != 0) |
| 75 | + { |
| 76 | + ulong Padding = BlockSize - (ESPLastLBA + 1) % BlockSize; |
| 77 | + throw new Exception("ESPLastLBA + 1 overflew block alignment by: " + Padding); |
| 78 | + } |
| 79 | + |
| 80 | + if (WindowsFirstLBA % BlockSize != 0) |
| 81 | + { |
| 82 | + ulong Padding = BlockSize - WindowsFirstLBA % BlockSize; |
| 83 | + throw new Exception("WindowsFirstLBA overflew block alignment by: " + Padding); |
| 84 | + } |
| 85 | + |
| 86 | + if ((WindowsLastLBA + 1) % BlockSize != 0) |
| 87 | + { |
| 88 | + ulong Padding = BlockSize - (WindowsLastLBA + 1) % BlockSize; |
| 89 | + throw new Exception("WindowsLastLBA + 1 overflew block alignment by: " + Padding); |
| 90 | + } |
| 91 | + |
| 92 | + Partitions.Add(new() |
| 93 | + { |
| 94 | + TypeGUID = new Guid("c12a7328-f81f-11d2-ba4b-00a0c93ec93b"), |
| 95 | + UID = new Guid("dec2832a-5f6c-430a-bd85-42551bce7b91"), |
| 96 | + FirstLBA = ESPFirstLBA, |
| 97 | + LastLBA = ESPLastLBA, |
| 98 | + Attributes = 0, |
| 99 | + Name = "esp" |
| 100 | + }); |
| 101 | + |
| 102 | + Partitions.Add(new() |
| 103 | + { |
| 104 | + TypeGUID = new Guid("ebd0a0a2-b9e5-4433-87c0-68b6b72699c7"), |
| 105 | + UID = new Guid("92dee62d-ed67-4ec3-9daa-c9a4bce2c355"), |
| 106 | + FirstLBA = WindowsFirstLBA, |
| 107 | + LastLBA = WindowsLastLBA, |
| 108 | + Attributes = 0, |
| 109 | + Name = "win" |
| 110 | + }); |
| 111 | + |
| 112 | + Partitions[^3].LastLBA = ESPFirstLBA - 1; |
| 113 | + |
| 114 | + ConsoleColor ogColor = Console.ForegroundColor; |
| 115 | + |
| 116 | + ulong androidSpaceInBytes = (Partitions[^3].LastLBA - Partitions[^3].FirstLBA) * SectorSize; |
| 117 | + ulong windowsSpaceInBytes = (Partitions[^1].LastLBA - Partitions[^1].FirstLBA) * SectorSize; |
| 118 | + |
| 119 | + Console.WriteLine("Resulting Allocation after Computation, Compatibility Checks and Corrections:"); |
| 120 | + Console.WriteLine(); |
| 121 | + Console.WriteLine("Android: " + Math.Round(androidSpaceInBytes / (double)(1024 * 1024 * 1024), 2) + "GB"); |
| 122 | + Console.WriteLine("Windows: " + Math.Round(windowsSpaceInBytes / (double)(1024 * 1024 * 1024), 2) + "GB"); |
| 123 | + Console.WriteLine(); |
| 124 | + |
| 125 | + Console.WriteLine("Resulting parted commands:"); |
| 126 | + Console.WriteLine(); |
| 127 | + Console.ForegroundColor = ConsoleColor.Green; |
| 128 | + Console.WriteLine($"mkpart {Partitions[^3].Name} ext4 {Partitions[^3].FirstLBA}s {Partitions[^3].LastLBA}s"); |
| 129 | + Console.WriteLine($"mkpart {Partitions[^2].Name} fat32 {Partitions[^2].FirstLBA}s {Partitions[^2].LastLBA}s"); |
| 130 | + Console.WriteLine($"mkpart {Partitions[^1].Name} ntfs {Partitions[^1].FirstLBA}s {Partitions[^1].LastLBA}s"); |
| 131 | + Console.ForegroundColor = ogColor; |
| 132 | + } |
| 133 | + } |
| 134 | +} |
0 commit comments