Add native format for small FAT32; fix MBR bugs

This commit is contained in:
Pdawg11239
2025-03-29 20:06:48 -04:00
parent 8505c06e66
commit ac42c67478
6 changed files with 63 additions and 32 deletions

View File

@@ -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;

View File

@@ -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 "";
}
}

View File

@@ -5,6 +5,7 @@ DeviceIoControl
CloseHandle
VirtualAlloc
VirtualFree
SetVolumeLabelW
GUID
DISK_GEOMETRY
PARTITION_INFORMATION

View File

@@ -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)
};

View File

@@ -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);
}
}
}

View File

@@ -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);