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

@@ -7,4 +7,11 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.183">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -5,5 +5,38 @@
internal const string ORANGE = "\u001b[38;2;255;114;0m";
internal const string ANSI_RESET = "\u001b[0m";
internal const uint GENERIC_READ = 0x80000000;
internal const uint GENERIC_WRITE = 0x40000000;
internal const uint OPEN_EXISTING = 3;
internal const uint FILE_SHARE_READ = 1;
internal const uint FILE_BEGIN = 0;
internal const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
internal const uint IOCTL_DISK_GET_DRIVE_GEOMETRY = 0x00070000;
internal const uint IOCTL_DISK_GET_PARTITION_INFO_EX = 0x00070048;
internal const uint IOCTL_DISK_GET_PARTITION_INFO = 0x00074004;
internal const uint IOCTL_DISK_SET_PARTITION_INFO = 0x0007C008;
internal const uint FSCTL_LOCK_VOLUME = 0x00090018;
internal const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
internal const uint FSCTL_UNLOCK_VOLUME = 0x0009001C;
internal const uint FSCTL_QUERY_RETRIEVAL_POINTERS = 0x0009003B;
internal const uint FSCTL_GET_COMPRESSION = 0x0009003C;
internal const uint FSCTL_SET_COMPRESSION = 0x0009C040;
internal const uint FSCTL_SET_BOOTLOADER_ACCESSED = 0x0009004F;
internal const uint FSCTL_MARK_AS_SYSTEM_HIVE = 0x0009004F;
internal const uint FSCTL_OPLOCK_BREAK_ACK_NO_2 = 0x00090050;
internal const uint FSCTL_INVALIDATE_VOLUMES = 0x00090054;
internal const uint FSCTL_QUERY_FAT_BPB = 0x00090058;
internal const uint FSCTL_REQUEST_FILTER_OPLOCK = 0x0009005C;
internal const uint FSCTL_FILESYSTEM_GET_STATISTICS = 0x00090060;
internal const uint FSCTL_GET_NTFS_VOLUME_DATA = 0x00090064;
internal const uint FSCTL_GET_NTFS_FILE_RECORD = 0x00090068;
internal const uint FSCTL_GET_VOLUME_BITMAP = 0x0009006F;
internal const uint FSCTL_GET_RETRIEVAL_POINTERS = 0x00090073;
internal const uint FSCTL_MOVE_FILE = 0x00090074;
internal const uint FSCTL_IS_VOLUME_DIRTY = 0x00090078;
internal const uint FSCTL_ALLOW_EXTENDED_DASD_IO = 0x00090083;
}
}

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.");
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()}");
using (var pDiskGeometry = NativePointer.Allocate<DISK_GEOMETRY>())
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)
{
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);
}
bytesPerSector = diskGeometry.BytesPerSector;
using (var pDrivePartInfo = NativePointer.Allocate<PARTITION_INFORMATION>())
diskGeometry = new DISK_GEOMETRY();
fixed (DISK_GEOMETRY* pDiskGeometry = &diskGeometry)
{
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."));
diskPartInfo = Marshal.PtrToStructure<PARTITION_INFORMATION>(pDrivePartInfo.Pointer);
return DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, null, 0, pDiskGeometry, (uint)sizeof(DISK_GEOMETRY), null, null);
}
}
using (var pDriveExPartInfo = NativePointer.Allocate<PARTITION_INFORMATION_EX>())
private static unsafe bool TryGetPartitionInfo(SafeFileHandle handle, ref DISK_GEOMETRY diskGeometry, out PARTITION_INFORMATION partitionInfo, out bool isGPT)
{
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."));
partitionInfo = new PARTITION_INFORMATION();
PARTITION_INFORMATION_EX diskExPartInfo = new();
isGPT = false;
exDiskPartInfo = Marshal.PtrToStructure<PARTITION_INFORMATION_EX>(pDriveExPartInfo.Pointer);
fixed (PARTITION_INFORMATION* pPartitionInfo = &partitionInfo)
{
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;
}
}
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)."));
private static bool IsValidFAT32Size(uint totalSectors) =>
totalSectors >= 65536 && totalSectors < 0xFFFFFFFF;
FAT32BootSector bootSector;
FAT32FsInfoSector fsInfo;
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);
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;
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
};
fatSize = CalculateFATSize(bootSector.TotalSectors, bootSector.ReservedSectorCount, bootSector.SectorsPerCluster, bootSector.NumberOfFATs, bytesPerSector);
Span<byte> rawBytes = MemoryMarshal.AsBytes(new Span<FAT32BootSector>(ref bootSector));
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 (bootSector.BytesPerSector != 512)
{
rawBytes[bootSector.BytesPerSector - 2] = 0x55;
rawBytes[bootSector.BytesPerSector - 1] = 0xAA;
}
if (!DeviceIoControl(driveHandle, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0, out cbRet, 0))
return (-1, Error("Failed to unlock the device."));
rawBytes[0] = 0xEB;
rawBytes[1] = 0x58;
rawBytes[2] = 0x90;
return (0, "");
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++)
{
uint sectorStart = (i == 0) ? 0 : (uint)bootSector.BackupBootSector;
WriteSector(driveHandle, sectorStart, 1, bytesPerSector, StructToBytes(bootSector));
WriteSector(driveHandle, sectorStart + 1, 1, bytesPerSector, StructToBytes(fsInfo));
}
for (int i = 0; i < bootSector.NumberOfFATs; i++)
{
uint sectorStart = bootSector.ReservedSectorCount + ((uint)i * bootSector.SectorsPerFAT);
WriteSector(driveHandle, sectorStart, 1, bytesPerSector, UintArrayToBytes(firstFATSector));
}
if (!isGPT)
{
SET_PARTITION_INFORMATION setPartInfo = new SET_PARTITION_INFORMATION
{
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,15 +5,10 @@ namespace BadBuilder.Formatter
// Reference: https://cscie92.dce.harvard.edu/spring2024/K70F120M/bootSector.h
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 512)]
internal struct FAT32BootSector
internal unsafe struct FAT32BootSector
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
internal byte[] JumpCode;
[FieldOffset(3)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal char[] OEMName;
[FieldOffset(0)] public fixed byte JumpCode[3];
[FieldOffset(3)] public fixed char OEMName[8];
[FieldOffset(11)] internal ushort BytesPerSector;
[FieldOffset(13)] internal byte SectorsPerCluster;
@@ -36,26 +31,15 @@ namespace BadBuilder.Formatter
[FieldOffset(48)] internal ushort FSInfoSector;
[FieldOffset(50)] internal ushort BackupBootSector;
[FieldOffset(52)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
internal byte[] Reserved;
[FieldOffset(52)] public fixed byte Reserved[12];
[FieldOffset(64)] internal byte DriveNumber;
[FieldOffset(65)] internal byte Reserved1;
[FieldOffset(66)] internal byte BootSignature;
[FieldOffset(67)] internal uint VolumeID;
[FieldOffset(71)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
internal char[] VolumeLabel;
[FieldOffset(82)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal char[] FileSystemType;
[FieldOffset(90)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 420)]
internal byte[] Reserved2;
[FieldOffset(64)] public byte DriveNumber;
[FieldOffset(65)] public byte Reserved1;
[FieldOffset(66)] public byte BootSignature;
[FieldOffset(67)] public uint VolumeID;
[FieldOffset(71)] public fixed char VolumeLabel[11];
[FieldOffset(82)] public fixed char FileSystemType[8];
[FieldOffset(90)] public fixed byte Reserved2[420];
[FieldOffset(510)] internal ushort Signature;
}

View File

@@ -5,21 +5,17 @@ namespace BadBuilder.Formatter
// Reference: https://cscie92.dce.harvard.edu/spring2024/K70F120M/fsInfo.h
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 512)]
internal struct FAT32FsInfoSector
internal unsafe struct FAT32FsInfoSector
{
[FieldOffset(0)] public uint LeadSignature;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)]
public byte[] Reserved1; // Zeros
[FieldOffset(4)] public fixed byte Reserved1[480]; // Zeros
[FieldOffset(484)] public uint StructureSignature;
[FieldOffset(488)] public uint FreeClusterCount;
[FieldOffset(492)] public uint NextFreeCluster;
[FieldOffset(496)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] Reserved2;
[FieldOffset(496)] public fixed byte Reserved2[12];
[FieldOffset(508)] public uint TrailSignature;
}

View File

@@ -0,0 +1,12 @@
CreateFileW
WriteFile
SetFilePointer
DeviceIoControl
CloseHandle
VirtualAlloc
VirtualFree
GUID
DISK_GEOMETRY
PARTITION_INFORMATION
PARTITION_INFORMATION_EX
SET_PARTITION_INFORMATION

View File

@@ -1,38 +1,23 @@
using static BadBuilder.Formatter.Win32;
using static BadBuilder.Formatter.Constants;
using Windows.Win32.Foundation;
using Windows.Win32.System.Memory;
using System.Runtime.InteropServices;
using static Windows.Win32.PInvoke;
using static BadBuilder.Formatter.Constants;
namespace BadBuilder.Formatter
{
static class FAT32Utilities
static class Utilities
{
internal struct NativePointer : IDisposable
internal static byte[] StructToBytes<T>(T @struct) where T : struct
{
internal IntPtr Pointer;
internal uint Size;
internal NativePointer(Type type)
{
uint size = (uint)Marshal.SizeOf(type);
Pointer = Marshal.AllocHGlobal((int)size);
Size = size;
Span<T> structSpan = MemoryMarshal.CreateSpan(ref @struct, 1);
Span<byte> byteSpan = MemoryMarshal.AsBytes(structSpan);
return byteSpan.ToArray();
}
public void Dispose()
{
if (Pointer != IntPtr.Zero)
{
Marshal.FreeHGlobal(Pointer);
Pointer = IntPtr.Zero;
Size = 0;
}
}
internal static byte[] UintArrayToBytes(uint[] array) => MemoryMarshal.AsBytes<uint>(array.AsSpan()).ToArray();
internal static NativePointer Allocate<T>() where T : struct
{
return new NativePointer(typeof(T));
}
}
internal static string Error(string error) => $"{ORANGE}[-]{ANSI_RESET} {error}";
internal static void ExitWithError(string error)
@@ -74,42 +59,55 @@ namespace BadBuilder.Formatter
};
internal static void SeekTo(IntPtr hDevice, uint sector, uint bytesPerSector)
internal static unsafe void SeekTo(SafeHandle hDevice, uint sector, uint bytesPerSector)
{
long offset = sector * bytesPerSector;
int lowOffset = (int)(offset & 0xFFFFFFFF);
int highOffset = (int)(offset >> 32);
SetFilePointer(hDevice, lowOffset, ref highOffset, FILE_BEGIN);
SetFilePointer(hDevice, lowOffset, &highOffset, Windows.Win32.Storage.FileSystem.SET_FILE_POINTER_MOVE_METHOD.FILE_BEGIN);
}
internal static void WriteSector(IntPtr hDevice, uint sector, uint numberOfSectors, uint bytesPerSector, byte[] data)
internal static unsafe void WriteSector(SafeHandle hDevice, uint sector, uint numberOfSectors, uint bytesPerSector, byte[] data)
{
uint bytesWritten;
SeekTo(hDevice, sector, bytesPerSector);
if (!WriteFile(hDevice, data, numberOfSectors * bytesPerSector, out bytesWritten, 0))
ExitWithError("Unable to write to write sectors to FAT32 device, exiting.");
fixed (byte* pData = &data[0])
{
if (!WriteFile(new HANDLE(hDevice.DangerousGetHandle()), pData, numberOfSectors * bytesPerSector, &bytesWritten, null))
ExitWithError($"Unable to write sectors to FAT32 device, exiting. GetLastError: {Marshal.GetLastWin32Error()}");
}
}
internal static void ZeroOutSectors(IntPtr hDevice, uint sector, uint numberOfSectors, uint bytesPerSector)
internal static unsafe void ZeroOutSectors(SafeHandle hDevice, uint sector, uint numberOfSectors, uint bytesPerSector)
{
const uint burstSize = 128;
uint writeSize;
uint bytesWritten;
byte[] zeroBuffer = new byte[bytesPerSector * burstSize];
Array.Clear(zeroBuffer);
byte* pZeroSector = (byte*)VirtualAlloc(null, bytesPerSector * burstSize, VIRTUAL_ALLOCATION_TYPE.MEM_COMMIT | VIRTUAL_ALLOCATION_TYPE.MEM_RESERVE, PAGE_PROTECTION_FLAGS.PAGE_READWRITE);
try
{
SeekTo(hDevice, sector, bytesPerSector);
while (numberOfSectors > 0)
{
writeSize = (numberOfSectors > burstSize) ? burstSize : numberOfSectors;
WriteSector(hDevice, sector, numberOfSectors, bytesPerSector, zeroBuffer);
if (!WriteFile(new HANDLE(hDevice.DangerousGetHandle()), pZeroSector, writeSize * bytesPerSector, &bytesWritten, null))
ExitWithError($"Unable to write sectors to FAT32 device, exiting. GetLastError: {Marshal.GetLastWin32Error()}");
numberOfSectors -= writeSize;
}
}
finally
{
VirtualFree(pZeroSector, bytesPerSector * burstSize, VIRTUAL_FREE_TYPE.MEM_RELEASE);
}
}
}
}

View File

@@ -1,238 +0,0 @@
using System.Runtime.InteropServices;
namespace BadBuilder.Formatter
{
static partial class Win32
{
internal const uint GENERIC_READ = 0x80000000;
internal const uint GENERIC_WRITE = 0x40000000;
internal const uint OPEN_EXISTING = 3;
internal const uint FILE_SHARE_READ = 1;
internal const uint FILE_BEGIN = 0;
internal const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
internal const uint IOCTL_DISK_GET_DRIVE_GEOMETRY = 0x00070000;
internal const uint IOCTL_DISK_GET_PARTITION_INFO_EX = 0x00070048;
internal const uint IOCTL_DISK_GET_PARTITION_INFO = 0x00074004;
internal const uint FSCTL_LOCK_VOLUME = 0x00090018;
internal const uint FSCTL_UNLOCK_VOLUME = 0x0009001C;
internal const uint FSCTL_QUERY_RETRIEVAL_POINTERS = 0x0009003B;
internal const uint FSCTL_GET_COMPRESSION = 0x0009003C;
internal const uint FSCTL_SET_COMPRESSION = 0x0009C040;
internal const uint FSCTL_SET_BOOTLOADER_ACCESSED = 0x0009004F;
internal const uint FSCTL_MARK_AS_SYSTEM_HIVE = 0x0009004F;
internal const uint FSCTL_OPLOCK_BREAK_ACK_NO_2 = 0x00090050;
internal const uint FSCTL_INVALIDATE_VOLUMES = 0x00090054;
internal const uint FSCTL_QUERY_FAT_BPB = 0x00090058;
internal const uint FSCTL_REQUEST_FILTER_OPLOCK = 0x0009005C;
internal const uint FSCTL_FILESYSTEM_GET_STATISTICS = 0x00090060;
internal const uint FSCTL_GET_NTFS_VOLUME_DATA = 0x00090064;
internal const uint FSCTL_GET_NTFS_FILE_RECORD = 0x00090068;
internal const uint FSCTL_GET_VOLUME_BITMAP = 0x0009006F;
internal const uint FSCTL_GET_RETRIEVAL_POINTERS = 0x00090073;
internal const uint FSCTL_MOVE_FILE = 0x00090074;
internal const uint FSCTL_IS_VOLUME_DIRTY = 0x00090078;
internal const uint FSCTL_ALLOW_EXTENDED_DASD_IO = 0x00090083;
private const string Kernel32 = "kernel32.dll";
[LibraryImport(Kernel32, SetLastError = true)]
internal static partial IntPtr CreateFileW(
[MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[LibraryImport(Kernel32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool WriteFile(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
[LibraryImport(Kernel32, SetLastError = true)]
internal static partial uint SetFilePointer(
IntPtr hFile,
int lDistanceToMove,
ref int lpDistanceToMoveHigh,
uint dwMoveMethod);
[LibraryImport(Kernel32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
[LibraryImport(Kernel32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool CloseHandle(IntPtr hObject);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct DISK_GEOMETRY
{
internal long Cylinders;
internal MediaType MediaType;
internal uint TracksPerCylinder;
internal uint SectorsPerTrack;
internal uint BytesPerSector;
}
internal enum MediaType // from winioctl.h
{
Unknown, // Format is unknown
F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector
F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector
F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector
F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector
F3_720_512, // 3.5", 720KB, 512 bytes/sector
F5_360_512, // 5.25", 360KB, 512 bytes/sector
F5_320_512, // 5.25", 320KB, 512 bytes/sector
F5_320_1024, // 5.25", 320KB, 1024 bytes/sector
F5_180_512, // 5.25", 180KB, 512 bytes/sector
F5_160_512, // 5.25", 160KB, 512 bytes/sector
RemovableMedia, // Removable media other than floppy
FixedMedia, // Fixed hard disk media
F3_120M_512, // 3.5", 120M Floppy
F3_640_512, // 3.5" , 640KB, 512 bytes/sector
F5_640_512, // 5.25", 640KB, 512 bytes/sector
F5_720_512, // 5.25", 720KB, 512 bytes/sector
F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector
F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector
F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector
F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector
F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector
F8_256_128, // 8", 256KB, 128 bytes/sector
F3_200Mb_512, // 3.5", 200M Floppy (HiFD)
F3_240M_512, // 3.5", 240Mb Floppy (HiFD)
F3_32M_512 // 3.5", 32Mb Floppy
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16)]
internal struct GUID
{
internal uint Data1;
internal ushort Data2;
internal ushort Data3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
internal byte[] Data4;
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 32)]
internal struct PARTITION_INFORMATION
{
internal long StartingOffset;
internal long PartitionLength;
internal uint HiddenSectors;
internal uint PartitionNumber;
internal byte PartitionType;
internal byte BootIndicator;
internal byte RecognizedPattern;
internal byte RewritePartition;
}
[StructLayout(LayoutKind.Explicit, Size = 144)]
internal struct PARTITION_INFORMATION_EX
{
[FieldOffset(0)]
internal PARTITION_STYLE PartitionStyle;
[FieldOffset(8)]
internal long StartingOffset;
[FieldOffset(16)]
internal long PartitionLength;
[FieldOffset(24)]
internal uint PartitionNumber;
[FieldOffset(28)]
internal byte RewritePartition;
[FieldOffset(29)]
internal byte IsServicePartition;
[FieldOffset(32)]
internal unsafe fixed byte Union[112];
public unsafe PARTITION_INFORMATION_MBR Mbr
{
get
{
fixed (byte* p = Union)
{
return *(PARTITION_INFORMATION_MBR*)p;
}
}
set
{
fixed (byte* p = Union)
{
*(PARTITION_INFORMATION_MBR*)p = value;
}
}
}
public unsafe PARTITION_INFORMATION_GPT Gpt
{
get
{
fixed (byte* p = Union)
{
return *(PARTITION_INFORMATION_GPT*)p;
}
}
set
{
fixed (byte* p = Union)
{
*(PARTITION_INFORMATION_GPT*)p = value;
}
}
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 24)]
internal struct PARTITION_INFORMATION_MBR
{
internal byte PartitionType;
internal byte BootIndicator;
internal byte RecognizedPartition;
private byte _padding1;
internal uint HiddenSectors;
internal GUID PartitionId;
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 112)]
internal struct PARTITION_INFORMATION_GPT
{
internal GUID PartitionType;
internal GUID PartitionId;
internal ulong Attributes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)]
internal ushort[] Name;
}
internal enum PARTITION_STYLE : uint
{
MBR = 0,
GPT = 1,
RAW = 2
}
}
}

View File

@@ -13,10 +13,6 @@
<None Remove="fat32format.exe" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\fat32format.exe" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Octokit" Version="14.0.0" />
<PackageReference Include="SharpCompress" Version="0.39.0" />

View File

@@ -1,11 +1,6 @@
using Spectre.Console;
using BadBuilder.Models;
using BadBuilder.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BadBuilder
{
@@ -38,15 +33,28 @@ namespace BadBuilder
);
}
static void FormatDisk(List<DiskInfo> disks, string selectedDisk)
static bool FormatDisk(List<DiskInfo> disks, string selectedDisk)
{
int diskIndex = disks.FindIndex(disk => $"{disk.DriveLetter} ({disk.SizeFormatted}) - {disk.Type}" == selectedDisk);
bool ret = true;
string output = string.Empty;
AnsiConsole.Status().SpinnerStyle(LightOrangeStyle).Start($"[#76B900]Formatting disk[/] {selectedDisk}", ctx =>
{
if (diskIndex == -1) return;
DiskHelper.FormatDisk(disks[diskIndex]).Wait();
output = DiskHelper.FormatDisk(disks[diskIndex]);
if (output != string.Empty) ret = false;
});
if (!ret)
{
AnsiConsole.Clear();
ShowWelcomeMessage();
Console.Write("\n" + output + "\n");
}
return ret;
}
}
}

View File

@@ -1,7 +1,7 @@
using Spectre.Console;
using BadBuilder.Helpers;
using static BadBuilder.Constants;
using static BadBuilder.Utilities.Constants;
namespace BadBuilder
{

View File

@@ -1,9 +1,4 @@
using Spectre.Console;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BadBuilder
{

View File

@@ -1,8 +1,9 @@
using SharpCompress.Archives;
using SharpCompress.Common;
using Spectre.Console;
using Spectre.Console;
using System.Diagnostics;
using static BadBuilder.Constants;
using SharpCompress.Common;
using SharpCompress.Archives;
using static BadBuilder.Utilities.Constants;
namespace BadBuilder.Helpers
{
@@ -27,7 +28,7 @@ namespace BadBuilder.Helpers
}
catch (Exception ex)
{
// Sorry, but these exceptions are invalid. SharpCompress is mad because there's nested ZIPs in xexmenu.
// Sorry, but these exceptions are invalid. The files extract just fine.
Debug.WriteLine(ex);
}
}

View File

@@ -1,6 +1,5 @@
using BadBuilder.Models;
using System.Diagnostics;
using System.Management;
using BadBuilder.Formatter;
namespace BadBuilder.Helpers
{
@@ -28,25 +27,6 @@ namespace BadBuilder.Helpers
return disks;
}
internal static async Task FormatDisk(DiskInfo disk)
{
ResourceHelper.ExtractEmbeddedBinary("fat32format.exe");
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = @"fat32format.exe",
Arguments = $"-c64 {disk.DriveLetter}",
RedirectStandardOutput = false,
RedirectStandardError = false,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
await process.WaitForExitAsync();
}
internal static string FormatDisk(DiskInfo disk) => DiskFormatter.FormatVolume(disk.DriveLetter.ToCharArray()[0]);
}
}

View File

@@ -1,7 +1,7 @@
using Octokit;
using Spectre.Console;
using static BadBuilder.Constants;
using static BadBuilder.Utilities.Constants;
namespace BadBuilder.Helpers
{

View File

@@ -1,6 +1,4 @@
using BadBuilder.Models;
namespace BadBuilder.Helpers
namespace BadBuilder.Helpers
{
internal static class FileSystemHelper
{

View File

@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BadBuilder.Helpers
{

View File

@@ -1,21 +0,0 @@
using System.Reflection;
namespace BadBuilder.Helpers
{
internal static class ResourceHelper
{
internal static void ExtractEmbeddedBinary(string resourceName)
{
var assembly = Assembly.GetExecutingAssembly();
string fullResourceName = $"BadBuilder.Resources.{resourceName}";
using (Stream resourceStream = assembly.GetManifestResourceStream(fullResourceName))
{
if (resourceStream == null) return;
using (FileStream fileStream = new FileStream($@"{resourceName}", FileMode.Create, FileAccess.Write))
resourceStream.CopyTo(fileStream);
}
}
}
}

View File

@@ -6,7 +6,8 @@ using Spectre.Console;
using BadBuilder.Models;
using BadBuilder.Helpers;
using static BadBuilder.Constants;
using static BadBuilder.Utilities.Constants;
using BadBuilder.Utilities;
namespace BadBuilder
{
@@ -26,7 +27,6 @@ namespace BadBuilder
static void Main(string[] args)
{
BadBuilder.Formatter.DiskFormatter.FormatVolume('E');
ShowWelcomeMessage();
while (true)
@@ -43,7 +43,7 @@ namespace BadBuilder
bool confirmation = PromptFormatConfirmation(selectedDisk);
if (confirmation)
{
FormatDisk(disks, selectedDisk);
if (!FormatDisk(disks, selectedDisk)) continue;
break;
}
}

Binary file not shown.

View File

@@ -1,4 +1,4 @@
namespace BadBuilder.Models
namespace BadBuilder.Utilities
{
internal class ActionQueue
{

View File

@@ -1,4 +1,4 @@
namespace BadBuilder
namespace BadBuilder.Utilities
{
internal static class Constants
{