Finish formatter

This commit is contained in:
Pdawg11239
2025-03-17 03:11:11 -04:00
parent 2a15f045bc
commit 7c0fb0d416
24 changed files with 332 additions and 482 deletions

View File

@@ -1,114 +1,220 @@
using static BadBuilder.Formatter.Win32;
using static BadBuilder.Formatter.Constants;
using static BadBuilder.Formatter.FAT32Utilities;
#pragma warning disable CA1416
using System.Text;
using Windows.Win32.System.Ioctl;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using Windows.Win32.Storage.FileSystem;
using static Windows.Win32.PInvoke;
using static BadBuilder.Formatter.Constants;
using static BadBuilder.Formatter.Utilities;
namespace BadBuilder.Formatter
{
public static class DiskFormatter
{
public static unsafe (int, string) FormatVolume(char driveLetter)
public static unsafe string FormatVolume(char driveLetter)
{
uint cbRet;
DISK_GEOMETRY diskGeometry;
PARTITION_INFORMATION diskPartInfo;
PARTITION_INFORMATION_EX exDiskPartInfo;
bool isGPT = false;
uint bytesPerSector = 0;
uint totalSectors;
uint fatSize;
string devicePath = $"\\\\.\\{driveLetter}:";
uint volumeID = GetVolumeID();
using SafeFileHandle driveHandle = OpenDeviceHandle(devicePath);
if (driveHandle.IsInvalid) return Error("Unable to open device. GetLastError: " + Marshal.GetLastWin32Error());
IntPtr driveHandle = CreateFileW(
devicePath,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
0);
if (!EnableExtendedDASDIO(driveHandle) || !LockDevice(driveHandle))
return Error("Failed to initialize device access.");
if (driveHandle == -1) return (-1, Error("Unable to open device - close all open programs or windows that may have a handle lock on the drive."));
DISK_GEOMETRY diskGeometry;
if (!TryGetDiskGeometry(driveHandle, out diskGeometry))
return Error("Failed to get drive geometry.");
if (!DeviceIoControl( driveHandle, FSCTL_ALLOW_EXTENDED_DASD_IO, 0, 0, 0, 0, out cbRet, 0))
return (-1, Error("Failed to enable extended DASD IO on the device."));
PARTITION_INFORMATION partitionInfo = new();
bool isGPT = false;
if (!TryGetPartitionInfo(driveHandle, ref diskGeometry, out partitionInfo, out isGPT))
return Error("Failed to get partition information.");
if (!DeviceIoControl(driveHandle, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, out cbRet, 0))
return (-1, Error("Failed to lock the device."));
uint totalSectors = (uint)(partitionInfo.PartitionLength / diskGeometry.BytesPerSector);
if (!IsValidFAT32Size(totalSectors))
return Error("Invalid drive size for FAT32.");
using (var pDiskGeometry = NativePointer.Allocate<DISK_GEOMETRY>())
FAT32BootSector bootSector = InitializeBootSector(diskGeometry, partitionInfo, totalSectors, volumeID);
FAT32FsInfoSector fsInfo = InitializeFsInfo();
uint[] firstFATSector = InitializeFirstFATSector(diskGeometry.BytesPerSector);
string formatOutput = FormatVolumeData(driveHandle, diskGeometry, bootSector, fsInfo, firstFATSector, isGPT, partitionInfo);
if (formatOutput != string.Empty)
return formatOutput;
if (!UnlockDevice(driveHandle) || !DismountVolume(driveHandle))
return Error($"Failed to release the device. GetLastError: {Marshal.GetLastWin32Error()}");
return string.Empty;
}
private static SafeFileHandle OpenDeviceHandle(string devicePath) =>
CreateFile(devicePath, GENERIC_READ | GENERIC_WRITE, 0, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_NO_BUFFERING, null);
private static unsafe bool EnableExtendedDASDIO(SafeFileHandle handle) =>
DeviceIoControl(handle, FSCTL_ALLOW_EXTENDED_DASD_IO, null, 0, null, 0, null, null);
private static unsafe bool LockDevice(SafeFileHandle handle) =>
DeviceIoControl(handle, FSCTL_LOCK_VOLUME, null, 0, null, 0, null, null);
private static unsafe bool UnlockDevice(SafeFileHandle handle) =>
DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, null, null);
private static unsafe bool DismountVolume(SafeFileHandle handle) =>
DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, null, null);
private static unsafe bool TryGetDiskGeometry(SafeFileHandle handle, out DISK_GEOMETRY diskGeometry)
{
diskGeometry = new DISK_GEOMETRY();
fixed (DISK_GEOMETRY* pDiskGeometry = &diskGeometry)
{
if (!DeviceIoControl(driveHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, 0, 0, pDiskGeometry.Pointer, pDiskGeometry.Size, out cbRet, 0))
return (-1, Error("Failed to get the drive geometry."));
diskGeometry = Marshal.PtrToStructure<DISK_GEOMETRY>(pDiskGeometry.Pointer);
return DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, null, 0, pDiskGeometry, (uint)sizeof(DISK_GEOMETRY), null, null);
}
bytesPerSector = diskGeometry.BytesPerSector;
}
using (var pDrivePartInfo = NativePointer.Allocate<PARTITION_INFORMATION>())
private static unsafe bool TryGetPartitionInfo(SafeFileHandle handle, ref DISK_GEOMETRY diskGeometry, out PARTITION_INFORMATION partitionInfo, out bool isGPT)
{
partitionInfo = new PARTITION_INFORMATION();
PARTITION_INFORMATION_EX diskExPartInfo = new();
isGPT = false;
fixed (PARTITION_INFORMATION* pPartitionInfo = &partitionInfo)
{
if (!DeviceIoControl(driveHandle, IOCTL_DISK_GET_PARTITION_INFO, 0, 0, pDrivePartInfo.Pointer, pDrivePartInfo.Size, out cbRet, 0))
return (-1, Error("Failed to get the drive partition information."));
if (!DeviceIoControl(handle, IOCTL_DISK_GET_PARTITION_INFO, null, 0, pPartitionInfo, (uint)sizeof(PARTITION_INFORMATION), null, null))
{
if (DeviceIoControl(handle, IOCTL_DISK_GET_PARTITION_INFO_EX, null, 0, &diskExPartInfo, (uint)sizeof(PARTITION_INFORMATION_EX), null, null))
{
partitionInfo = new PARTITION_INFORMATION
{
StartingOffset = diskExPartInfo.StartingOffset,
PartitionLength = diskExPartInfo.PartitionLength,
HiddenSectors = (uint)(diskExPartInfo.StartingOffset / diskGeometry.BytesPerSector)
};
isGPT = (diskExPartInfo.PartitionStyle == PARTITION_STYLE.PARTITION_STYLE_GPT);
return true;
}
return false;
}
return true;
}
}
diskPartInfo = Marshal.PtrToStructure<PARTITION_INFORMATION>(pDrivePartInfo.Pointer);
private static bool IsValidFAT32Size(uint totalSectors) =>
totalSectors >= 65536 && totalSectors < 0xFFFFFFFF;
private static unsafe FAT32BootSector InitializeBootSector(DISK_GEOMETRY diskGeometry, PARTITION_INFORMATION partitionInfo, uint totalSectors, uint volumeID)
{
byte sectorsPerCluster = CalculateSectorsPerCluster((ulong)partitionInfo.PartitionLength, diskGeometry.BytesPerSector);
uint fatSize = CalculateFATSize(totalSectors, 32, sectorsPerCluster, 2, diskGeometry.BytesPerSector);
FAT32BootSector bootSector = new FAT32BootSector
{
BytesPerSector = (ushort)diskGeometry.BytesPerSector,
SectorsPerCluster = sectorsPerCluster,
ReservedSectorCount = 32,
NumberOfFATs = 2,
MediaDescriptor = 0xF8,
SectorsPerTrack = (ushort)diskGeometry.SectorsPerTrack,
NumberOfHeads = (ushort)diskGeometry.TracksPerCylinder,
HiddenSectors = partitionInfo.HiddenSectors,
TotalSectors = totalSectors,
SectorsPerFAT = fatSize,
RootCluster = 2,
FSInfoSector = 1,
BackupBootSector = 6,
DriveNumber = 0x80,
BootSignature = 0x29,
VolumeID = volumeID,
Signature = 0x55AA
};
Span<byte> rawBytes = MemoryMarshal.AsBytes(new Span<FAT32BootSector>(ref bootSector));
if (bootSector.BytesPerSector != 512)
{
rawBytes[bootSector.BytesPerSector - 2] = 0x55;
rawBytes[bootSector.BytesPerSector - 1] = 0xAA;
}
using (var pDriveExPartInfo = NativePointer.Allocate<PARTITION_INFORMATION_EX>())
rawBytes[0] = 0xEB;
rawBytes[1] = 0x58;
rawBytes[2] = 0x90;
string oemName = "MSWIN4.1";
Encoding.ASCII.GetBytes(oemName).CopyTo(rawBytes.Slice(3, 8));
string volumeLabel = "BADUPDATE ";
Encoding.ASCII.GetBytes(volumeLabel).CopyTo(rawBytes.Slice(71, 11));
string fileSystemType = "FAT32 ";
Encoding.ASCII.GetBytes(fileSystemType).CopyTo(rawBytes.Slice(82, 8));
return bootSector;
}
private static FAT32FsInfoSector InitializeFsInfo() => new FAT32FsInfoSector
{
LeadSignature = 0x41615252,
StructureSignature = 0x61417272,
TrailSignature = 0xAA550000,
FreeClusterCount = 0,
NextFreeCluster = 3
};
private static uint[] InitializeFirstFATSector(uint bytesPerSector)
{
uint[] sector = new uint[bytesPerSector / 4];
sector[0] = 0x0FFFFFF8;
sector[1] = 0x0FFFFFFF;
sector[2] = 0x0FFFFFFF;
return sector;
}
private static unsafe string FormatVolumeData(SafeFileHandle driveHandle, DISK_GEOMETRY geometry, FAT32BootSector bootSector, FAT32FsInfoSector fsInfo, uint[] firstFATSector, bool isGPT, PARTITION_INFORMATION partitionInfo)
{
uint bytesPerSector = geometry.BytesPerSector;
uint totalSectors = (uint)(partitionInfo.PartitionLength / geometry.BytesPerSector);
uint userAreaSize = totalSectors - bootSector.ReservedSectorCount - (bootSector.NumberOfFATs * bootSector.SectorsPerFAT);
uint systemAreaSize = bootSector.ReservedSectorCount + (bootSector.NumberOfFATs * bootSector.SectorsPerFAT) + bootSector.SectorsPerCluster;
uint clusterCount = userAreaSize / bootSector.SectorsPerCluster;
if (clusterCount < 65536 || clusterCount > 0x0FFFFFFF)
return Error("The drives cluster count is out of range (65536 < clusterCount < 0x0FFFFFFF)");
fsInfo.FreeClusterCount = (userAreaSize / bootSector.SectorsPerCluster) - 1;
ZeroOutSectors(driveHandle, 0, systemAreaSize, bytesPerSector);
for (int i = 0; i < 2; i++)
{
if (!DeviceIoControl(driveHandle, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, pDriveExPartInfo.Pointer, pDriveExPartInfo.Size, out cbRet, 0))
return (-1, Error("Failed to get the drive extended partition information."));
exDiskPartInfo = Marshal.PtrToStructure<PARTITION_INFORMATION_EX>(pDriveExPartInfo.Pointer);
uint sectorStart = (i == 0) ? 0 : (uint)bootSector.BackupBootSector;
WriteSector(driveHandle, sectorStart, 1, bytesPerSector, StructToBytes(bootSector));
WriteSector(driveHandle, sectorStart + 1, 1, bytesPerSector, StructToBytes(fsInfo));
}
isGPT = (exDiskPartInfo.PartitionStyle == PARTITION_STYLE.GPT);
totalSectors = (uint)(diskPartInfo.PartitionLength / diskGeometry.BytesPerSector);
if (totalSectors < 65536 || totalSectors >= 0xffffffff)
return (-1, Error("Invalid drive size for FAT32 - either too small (less than 64K clusters) or too large (greater than 2TB)."));
for (int i = 0; i < bootSector.NumberOfFATs; i++)
{
uint sectorStart = bootSector.ReservedSectorCount + ((uint)i * bootSector.SectorsPerFAT);
WriteSector(driveHandle, sectorStart, 1, bytesPerSector, UintArrayToBytes(firstFATSector));
}
FAT32BootSector bootSector;
FAT32FsInfoSector fsInfo;
if (!isGPT)
{
SET_PARTITION_INFORMATION setPartInfo = new SET_PARTITION_INFORMATION
{
PartitionType = 0x0C
};
bootSector.JumpCode = [0xEB, 0x58, 0x90];
bootSector.OEMName = "MSWIN4.1".ToCharArray();
bootSector.BytesPerSector = (ushort)bytesPerSector;
bootSector.SectorsPerCluster = CalculateSectorsPerCluster((ulong)diskPartInfo.PartitionLength, bytesPerSector);
bootSector.ReservedSectorCount = 32;
bootSector.NumberOfFATs = 2;
bootSector.MaxRootEntries = 0;
bootSector.TotalSectors16 = 0;
bootSector.MediaDescriptor = 0xF8;
bootSector.SectorsPerFAT16 = 0;
bootSector.SectorsPerTrack = (ushort)diskGeometry.SectorsPerTrack;
bootSector.NumberOfHeads = (ushort)diskGeometry.TracksPerCylinder;
bootSector.HiddenSectors = diskPartInfo.HiddenSectors;
bootSector.TotalSectors = totalSectors;
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()}");
}
fatSize = CalculateFATSize(bootSector.TotalSectors, bootSector.ReservedSectorCount, bootSector.SectorsPerCluster, bootSector.NumberOfFATs, bytesPerSector);
bootSector.SectorsPerFAT = fatSize;
bootSector.FATFlags = 0;
bootSector.FileSystemVersion = 0;
bootSector.RootCluster = 2;
bootSector.FSInfoSector = 1;
bootSector.BackupBootSector = 6;
bootSector.DriveNumber = 0x80;
bootSector.Reserved1 = 0;
bootSector.BootSignature = 0x29;
bootSector.VolumeID = volumeID;
bootSector.VolumeLabel = "BADUPDATE ".ToCharArray();
bootSector.FileSystemType = "FAT32 ".ToCharArray();
bootSector.Signature = 0x55AA;
if (!DeviceIoControl(driveHandle, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0, out cbRet, 0))
return (-1, Error("Failed to unlock the device."));
return (0, "");
return "";
}
}
}
}