Add native format for small FAT32; fix MBR bugs
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ DeviceIoControl
|
||||
CloseHandle
|
||||
VirtualAlloc
|
||||
VirtualFree
|
||||
SetVolumeLabelW
|
||||
GUID
|
||||
DISK_GEOMETRY
|
||||
PARTITION_INFORMATION
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user