/// <summary>
/// Formats the partition with specified fat settings.
/// </summary>
/// <param name="fatSettings">The fat settings.</param>
/// <returns></returns>
public bool Format(FatSettings fatSettings)
{
if (!partition.CanWrite)
return false;
this.fatType = fatSettings.FATType;
bytesPerSector = 512;
nbrFats = 2;
totalSectors = partition.BlockCount;
sectorsPerCluster = GetSectorsPerClusterByTotalSectors(fatType, totalSectors);
if (sectorsPerCluster == 0)
return false;
if (fatType == FatType.FAT32)
{
reservedSectors = 32;
rootEntries = 0;
}
else
{
reservedSectors = 1;
rootEntries = 512;
}
rootDirSectors = (((rootEntries * 32) + (bytesPerSector - 1)) / bytesPerSector);
uint val1 = totalSectors - (reservedSectors + rootDirSectors);
uint val2 = (uint)((sectorsPerCluster * 256) + nbrFats);
if (fatType == FatType.FAT32)
val2 = val2 / 2;
uint sectorsPerFat = (val1 + (val2 - 1)) / val2;
firstRootDirectorySector = reservedSectors + sectorsPerFat;
BinaryFormat bootSector = new BinaryFormat(512);
bootSector.SetUInt(BootSector.JumpInstruction, 0);
bootSector.SetString(BootSector.EOMName, "MOSA ");
bootSector.SetUShort(BootSector.BytesPerSector, (ushort)bytesPerSector);
bootSector.SetByte(BootSector.SectorsPerCluster, (byte)sectorsPerCluster);
bootSector.SetUShort(BootSector.ReservedSectors, (ushort)reservedSectors);
bootSector.SetByte(BootSector.FatAllocationTables, nbrFats);
bootSector.SetUShort(BootSector.MaxRootDirEntries, (ushort)rootEntries);
bootSector.SetUShort(BootSector.BootSectorSignature, 0xAA55);
if (totalSectors > 0xFFFF)
{
bootSector.SetUShort(BootSector.TotalSectors16, 0);
bootSector.SetUInt(BootSector.TotalSectors32, totalSectors);
}
else
{
bootSector.SetUShort(BootSector.TotalSectors16, (ushort)totalSectors);
bootSector.SetUInt(BootSector.TotalSectors32, 0);
}
if (fatSettings.FloppyMedia)
{
// Default is 1.44
bootSector.SetByte(BootSector.MediaDescriptor, 0xF0); // 0xF0 = 3.5" Double Sided, 80 tracks per side, 18 sectors per track (1.44MB).
}
else
bootSector.SetByte(BootSector.MediaDescriptor, 0xF8); // 0xF8 = Hard disk
bootSector.SetUShort(BootSector.SectorsPerTrack, fatSettings.SectorsPerTrack);
bootSector.SetUShort(BootSector.NumberOfHeads, fatSettings.NumberOfHeads);
bootSector.SetUInt(BootSector.HiddenSectors, fatSettings.HiddenSectors);
if (fatType != FatType.FAT32)
{
bootSector.SetUShort(BootSector.SectorsPerFAT, (ushort)sectorsPerFat);
if (fatSettings.FloppyMedia)
bootSector.SetByte(BootSector.PhysicalDriveNbr, 0x00);
else
bootSector.SetByte(BootSector.PhysicalDriveNbr, 0x80);
bootSector.SetByte(BootSector.ReservedCurrentHead, 0);
bootSector.SetByte(BootSector.ExtendedBootSignature, 0x29);
bootSector.SetBytes(BootSector.IDSerialNumber, fatSettings.SerialID, 0, (uint)Math.Min(4, fatSettings.SerialID.Length));
if (string.IsNullOrEmpty(fatSettings.VolumeLabel))
bootSector.SetString(BootSector.VolumeLabel, "NO NAME ");
else
{
bootSector.SetString(BootSector.VolumeLabel, " "); // 11 blank spaces
bootSector.SetString(BootSector.VolumeLabel, fatSettings.VolumeLabel, (uint)Math.Min(11, fatSettings.VolumeLabel.Length));
}
if (fatSettings.OSBootCode != null)
{
if (fatSettings.OSBootCode.Length == 512)
{
bootSector.SetBytes(BootSector.JumpInstruction, fatSettings.OSBootCode, BootSector.JumpInstruction, 3);
bootSector.SetBytes(BootSector.OSBootCode, fatSettings.OSBootCode, BootSector.OSBootCode, 448);
}
else
{
bootSector.SetByte(BootSector.JumpInstruction, 0xEB); // 0xEB = JMP Instruction
bootSector.SetByte(BootSector.JumpInstruction + 1, 0x3C);
bootSector.SetByte(BootSector.JumpInstruction + 2, 0x90);
bootSector.SetBytes(BootSector.OSBootCode, fatSettings.OSBootCode, 0, (uint)Math.Min(448, fatSettings.OSBootCode.Length));
}
}
if (fatType == FatType.FAT12)
bootSector.SetString(BootSector.FATType, "FAT12 ");
else
bootSector.SetString(BootSector.FATType, "FAT16 ");
}
if (fatType == FatType.FAT32)
{
bootSector.SetUShort(BootSector.SectorsPerFAT, 0);
bootSector.SetUInt(BootSector.FAT32_SectorPerFAT, sectorsPerFat);
bootSector.SetByte(BootSector.FAT32_Flags, 0);
bootSector.SetUShort(BootSector.FAT32_Version, 0);
bootSector.SetUInt(BootSector.FAT32_ClusterNumberOfRoot, 2);
bootSector.SetUShort(BootSector.FAT32_SectorFSInformation, 1);
bootSector.SetUShort(BootSector.FAT32_SecondBootSector, 6);
bootSector.SetByte(BootSector.FAT32_PhysicalDriveNbr, 0x80);
bootSector.SetByte(BootSector.FAT32_Reserved2, 0);
bootSector.SetByte(BootSector.FAT32_ExtendedBootSignature, 0x29);
bootSector.SetBytes(BootSector.FAT32_IDSerialNumber, fatSettings.SerialID, 0, (uint)Math.Min(4, fatSettings.SerialID.Length));
bootSector.SetString(BootSector.FAT32_VolumeLabel, " "); // 11 blank spaces
bootSector.SetString(BootSector.FAT32_VolumeLabel, fatSettings.VolumeLabel, (uint)(fatSettings.VolumeLabel.Length <= 11 ? fatSettings.VolumeLabel.Length : 11));
bootSector.SetString(BootSector.FAT32_FATType, "FAT32 ");
if (fatSettings.OSBootCode.Length == 512)
{
bootSector.SetBytes(BootSector.JumpInstruction, fatSettings.OSBootCode, BootSector.JumpInstruction, 3);
bootSector.SetBytes(BootSector.FAT32_OSBootCode, fatSettings.OSBootCode, BootSector.FAT32_OSBootCode, 420);
}
else
{
bootSector.SetByte(BootSector.JumpInstruction, 0xEB); // 0xEB = JMP Instruction
bootSector.SetByte(BootSector.JumpInstruction + 1, 0x58);
bootSector.SetByte(BootSector.JumpInstruction + 2, 0x90);
bootSector.SetBytes(BootSector.FAT32_OSBootCode, fatSettings.OSBootCode, 0, (uint)Math.Min(420, fatSettings.OSBootCode.Length));
}
}
// Write Boot Sector
partition.WriteBlock(0, 1, bootSector.Data);
if (fatType == FatType.FAT32)
{
// Write backup Boot Sector
if (fatType == FatType.FAT32)
partition.WriteBlock(6, 1, bootSector.Data);
// Create FSInfo Structure
BinaryFormat infoSector = new BinaryFormat(512);
infoSector.SetUInt(FSInfo.FSI_LeadSignature, 0x41615252);
//FSInfo.FSI_Reserved1
infoSector.SetUInt(FSInfo.FSI_StructureSigature, 0x61417272);
infoSector.SetUInt(FSInfo.FSI_FreeCount, 0xFFFFFFFF);
infoSector.SetUInt(FSInfo.FSI_NextFree, 0xFFFFFFFF);
//FSInfo.FSI_Reserved2
bootSector.SetUInt(FSInfo.FSI_TrailSignature, 0xAA550000);
// Write FSInfo Structure
partition.WriteBlock(1, 1, infoSector.Data);
partition.WriteBlock(7, 1, infoSector.Data);
// Create 2nd sector
BinaryFormat secondSector = new BinaryFormat(512);
secondSector.SetUShort(FSInfo.FSI_TrailSignature2, 0xAA55);
partition.WriteBlock(2, 1, secondSector.Data);
partition.WriteBlock(8, 1, secondSector.Data);
}
// Create FAT table(s)
// Clear primary & secondary FATs
BinaryFormat emptyFat = new BinaryFormat(512);
for (uint i = 1; i < sectorsPerFat; i++)
partition.WriteBlock(reservedSectors + i, 1, emptyFat.Data);
if (nbrFats == 2)
for (uint i = 1; i < sectorsPerFat; i++)
partition.WriteBlock(reservedSectors + sectorsPerFat + i, 1, emptyFat.Data);
// First FAT block is special
BinaryFormat firstFat = new BinaryFormat(512);
if (fatType == FatType.FAT12)
{
firstFat.SetByte(1, 0xFF);
firstFat.SetByte(2, 0xFF); // 0xF8
}
else if (fatType == FatType.FAT16)
{
firstFat.SetUShort(0, 0xFFFF);
firstFat.SetUShort(2, 0xFFFF); // 0xFFF8
}
else // if (type == FatType.FAT32)
{
firstFat.SetUInt(0, 0x0FFFFFFF);
firstFat.SetUInt(4, 0x0FFFFFFF); // 0x0FFFFFF8
firstFat.SetUInt(8, 0x0FFFFFFF); // Also reserve the 2nd cluster for root directory
}
if (fatSettings.FloppyMedia)
firstFat.SetByte(0, 0xF0);
else
firstFat.SetByte(0, 0xF8);
partition.WriteBlock(reservedSectors, 1, firstFat.Data);
if (nbrFats == 2)
partition.WriteBlock(reservedSectors + sectorsPerFat, 1, firstFat.Data);
// Create Empty Root Directory
if (fatType == FatType.FAT32)
{
}
else
{
for (uint i = 0; i < rootDirSectors; i++)
partition.WriteBlock(firstRootDirectorySector + i, 1, emptyFat.Data);
}
return ReadBootSector();
}