diff --git a/BadBuilder.Formatter/Constants.cs b/BadBuilder.Formatter/Constants.cs index 474a431..dc56dac 100644 --- a/BadBuilder.Formatter/Constants.cs +++ b/BadBuilder.Formatter/Constants.cs @@ -6,6 +6,12 @@ internal const string ANSI_RESET = "\u001b[0m"; + internal const long KB = 1024L; + internal const long MB = 1048576L; + internal const long GB = 1073741824L; + internal const long TB = 1099511627776L; + + internal const int FMIFS_HARDDISK = 0xC; internal const uint GENERIC_READ = 0x80000000; internal const uint GENERIC_WRITE = 0x40000000; diff --git a/BadBuilder.Formatter/DiskFormatter.cs b/BadBuilder.Formatter/DiskFormatter.cs index 23ecddc..7aa1d75 100644 --- a/BadBuilder.Formatter/DiskFormatter.cs +++ b/BadBuilder.Formatter/DiskFormatter.cs @@ -1,5 +1,6 @@ #pragma warning disable CA1416 using System.Text; +using System.Diagnostics; using Windows.Win32.System.Ioctl; using Microsoft.Win32.SafeHandles; using System.Runtime.InteropServices; @@ -8,17 +9,40 @@ using Windows.Win32.Storage.FileSystem; using static Windows.Win32.PInvoke; using static BadBuilder.Formatter.Constants; using static BadBuilder.Formatter.Utilities; +using Windows.Win32.Foundation; namespace BadBuilder.Formatter { public static class DiskFormatter { - public static unsafe string FormatVolume(char driveLetter) + public static unsafe string FormatVolume(char driveLetter, long diskSize) { + if (diskSize < 32 * GB) + { + Process process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "format.com", + Arguments = $"\"{driveLetter}:\" /Q /X /Y /FS:FAT32 /V:BADUPDATE", + RedirectStandardOutput = false, + RedirectStandardError = false, + UseShellExecute = false, + CreateNoWindow = true + } + }; + + process.Start(); + process.WaitForExit(); + + if (process.ExitCode == 0) return ""; + else return Error($"Native format failed with exit code: {process.ExitCode}"); + } + string devicePath = $"\\\\.\\{driveLetter}:"; uint volumeID = GetVolumeID(); - using SafeFileHandle driveHandle = OpenDeviceHandle(devicePath); + SafeFileHandle driveHandle = OpenDeviceHandle(devicePath); if (driveHandle.IsInvalid) return Error("Unable to open device. GetLastError: " + Marshal.GetLastWin32Error()); if (!EnableExtendedDASDIO(driveHandle) || !LockDevice(driveHandle)) @@ -48,6 +72,10 @@ namespace BadBuilder.Formatter if (!UnlockDevice(driveHandle) || !DismountVolume(driveHandle)) return Error($"Failed to release the device. GetLastError: {Marshal.GetLastWin32Error()}"); + driveHandle.Dispose(); + + if (!SetVolumeLabel($"{driveLetter}:", "BADUPDATE")) + return Error($"Unable to set volume label. GetLastError: {Marshal.GetLastWin32Error()}"); return string.Empty; } @@ -109,14 +137,18 @@ namespace BadBuilder.Formatter private static unsafe FAT32BootSector InitializeBootSector(DISK_GEOMETRY diskGeometry, PARTITION_INFORMATION partitionInfo, uint totalSectors, uint volumeID) { - byte sectorsPerCluster = CalculateSectorsPerCluster((ulong)partitionInfo.PartitionLength, diskGeometry.BytesPerSector); + uint sectorsPerCluster = (uint)CalculateSectorsPerCluster((ulong)partitionInfo.PartitionLength, diskGeometry.BytesPerSector); uint fatSize = CalculateFATSize(totalSectors, 32, sectorsPerCluster, 2, diskGeometry.BytesPerSector); + uint aligned = (uint)MB / diskGeometry.BytesPerSector; + uint sysAreaSize = ((34 * fatSize + aligned - 1) / aligned) * aligned; + uint reserved = sysAreaSize - 2 * fatSize; + FAT32BootSector bootSector = new FAT32BootSector { BytesPerSector = (ushort)diskGeometry.BytesPerSector, - SectorsPerCluster = sectorsPerCluster, - ReservedSectorCount = 32, + SectorsPerCluster = (byte)sectorsPerCluster, + ReservedSectorCount = (ushort)reserved, NumberOfFATs = 2, MediaDescriptor = 0xF8, SectorsPerTrack = (ushort)diskGeometry.SectorsPerTrack, @@ -186,8 +218,8 @@ namespace BadBuilder.Formatter { uint bytesPerSector = diskGeometry.BytesPerSector; uint totalSectors = (uint)(partitionInfo.PartitionLength / bytesPerSector); - uint systemAreaSize = bootSector.ReservedSectorCount + (bootSector.NumberOfFATs * bootSector.SectorsPerFAT) + bootSector.SectorsPerCluster; - uint userAreaSize = totalSectors - systemAreaSize; + uint userAreaSize = totalSectors - bootSector.ReservedSectorCount - (bootSector.NumberOfFATs * bootSector.SectorsPerFAT); + uint zeroOut = bootSector.ReservedSectorCount + (bootSector.NumberOfFATs * bootSector.SectorsPerFAT) + bootSector.SectorsPerCluster; uint clusterCount = userAreaSize / bootSector.SectorsPerCluster; if (clusterCount < 65536 || clusterCount > 0x0FFFFFFF) @@ -195,7 +227,7 @@ namespace BadBuilder.Formatter fsInfo.FreeClusterCount = clusterCount - 1; - ZeroOutSectors(driveHandle, 0, systemAreaSize, bytesPerSector); + ZeroOutSectors(driveHandle, 0, zeroOut, bytesPerSector); for (int i = 0; i < 2; i++) { @@ -210,14 +242,6 @@ namespace BadBuilder.Formatter WriteSector(driveHandle, sectorStart, 1, bytesPerSector, UintArrayToBytes(firstFATSector)); } - if (!isGPT) - { - SET_PARTITION_INFORMATION setPartInfo = new() { PartitionType = 0x0C }; - - if (!DeviceIoControl(driveHandle, IOCTL_DISK_SET_PARTITION_INFO, &setPartInfo, (uint)sizeof(SET_PARTITION_INFORMATION), null, 0, null, null)) - return Error($"Failed to set the drive partition information. GetLastError: {Marshal.GetLastWin32Error()}"); - } - return ""; } } diff --git a/BadBuilder.Formatter/NativeMethods.txt b/BadBuilder.Formatter/NativeMethods.txt index fd019bf..7c42be3 100644 --- a/BadBuilder.Formatter/NativeMethods.txt +++ b/BadBuilder.Formatter/NativeMethods.txt @@ -5,6 +5,7 @@ DeviceIoControl CloseHandle VirtualAlloc VirtualFree +SetVolumeLabelW GUID DISK_GEOMETRY PARTITION_INFORMATION diff --git a/BadBuilder.Formatter/Utilities.cs b/BadBuilder.Formatter/Utilities.cs index dea4ba4..448ad18 100644 --- a/BadBuilder.Formatter/Utilities.cs +++ b/BadBuilder.Formatter/Utilities.cs @@ -39,23 +39,27 @@ namespace BadBuilder.Formatter return (uint)(low | (hi << 16)); } - internal static uint CalculateFATSize(uint totalSectors, uint reservedSectors, uint sectorsPerCluster, uint numberOfFATs, uint bytesPerSector) + internal static uint CalculateFATSize(uint diskSize, uint reservedSectors, uint sectorsPerCluster, uint numberOfFATs, uint bytesPerSector) { const ulong fatElementSize = 4; + const ulong reservedClusters = 2; - ulong numerator = fatElementSize * (totalSectors - reservedSectors); - ulong denominator = (sectorsPerCluster * bytesPerSector) + (fatElementSize * numberOfFATs); + ulong numerator = diskSize - reservedSectors + reservedClusters * sectorsPerCluster; + ulong denominator = (sectorsPerCluster * bytesPerSector / fatElementSize) + numberOfFATs; - return (uint)((numerator / denominator) + 1); + return (uint)(numerator / denominator + 1); } - internal static byte CalculateSectorsPerCluster(ulong diskSizeBytes, uint bytesPerSector) => (diskSizeBytes / (1024 * 1024)) switch + internal static long CalculateSectorsPerCluster(ulong diskSizeBytes, uint bytesPerSector) => diskSizeBytes switch { - var size when size > 512 => (byte)((4 * 1024) / bytesPerSector), - var size when size > 8192 => (byte)((8 * 1024) / bytesPerSector), - var size when size > 16384 => (byte)((16 * 1024) / bytesPerSector), - var size when size > 32768 => (byte)((32 * 1024) / bytesPerSector), - _ => 1 + < 64 * MB => ((512) / bytesPerSector), + < 128 * MB => ((1 * KB) / bytesPerSector), + < 256 * MB => ((2 * KB) / bytesPerSector), + < 8 * GB => ((4 * KB) / bytesPerSector), + < 16 * GB => ((8 * KB) / bytesPerSector), + < 32 * GB => ((16 * KB) / bytesPerSector), + < 2 * TB => ((32 * KB) / bytesPerSector), + _ => ((64 * KB) / bytesPerSector) }; diff --git a/BadBuilder/Helpers/DiskHelper.cs b/BadBuilder/Helpers/DiskHelper.cs index 9631654..f7e48e3 100644 --- a/BadBuilder/Helpers/DiskHelper.cs +++ b/BadBuilder/Helpers/DiskHelper.cs @@ -34,7 +34,7 @@ namespace BadBuilder.Helpers if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return "\u001b[38;2;255;114;0m[-]\u001b[0m Formatting is currently only supported on Windows. Please format your drive manually and try again."; - return DiskFormatter.FormatVolume(disk.DriveLetter[0]); + return DiskFormatter.FormatVolume(disk.DriveLetter[0], disk.TotalSize); } } } \ No newline at end of file diff --git a/BadBuilder/Program.cs b/BadBuilder/Program.cs index 42f4d80..bc3614c 100644 --- a/BadBuilder/Program.cs +++ b/BadBuilder/Program.cs @@ -5,9 +5,9 @@ global using HomebrewApp = (string name, string folder, string entryPoint); using Spectre.Console; using BadBuilder.Models; using BadBuilder.Helpers; +using BadBuilder.Utilities; using static BadBuilder.Utilities.Constants; -using BadBuilder.Utilities; namespace BadBuilder { @@ -79,14 +79,10 @@ namespace BadBuilder actionQueue.EnqueueAction(async () => { using (StreamWriter writer = new(Path.Combine(TargetDriveLetter, "name.txt"))) - { writer.WriteLine("USB Storage Device"); - } using (StreamWriter writer = new(Path.Combine(TargetDriveLetter, "info.txt"))) - { writer.WriteLine("This drive was created with BadBuilder by Pdawg.\nFind more info here: https://github.com/Pdawg-bytes/BadBuilder"); - } Directory.CreateDirectory(Path.Combine(TargetDriveLetter, "Apps")); await FileSystemHelper.MirrorDirectoryAsync(Path.Combine(folder, "Rock Band Blitz"), TargetDriveLetter);