Skip to content

Commit cc2516a

Browse files
committed
Support for FAT with sector size > 512
1 parent 9652ff7 commit cc2516a

File tree

3 files changed

+35
-19
lines changed

3 files changed

+35
-19
lines changed

Library/DiscUtils.Fat/FatFileSystem.cs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,8 @@ public static bool Detect(Stream stream)
348348
Span<byte> bytes = stackalloc byte[512];
349349
stream.ReadExactly(bytes);
350350
var bpbBytesPerSec = EndianUtilities.ToUInt16LittleEndian(bytes.Slice(11));
351-
if (bpbBytesPerSec != 512)
351+
352+
if (bpbBytesPerSec < 512 || !MathUtilities.IsPowerOfTwo(bpbBytesPerSec))
352353
{
353354
return false;
354355
}
@@ -1449,7 +1450,7 @@ private static void WriteBPB(
14491450
uint volId,
14501451
string label)
14511452
{
1452-
var fatSectors = CalcFatSize(sectors, fatType, sectorsPerCluster);
1453+
var fatSectors = CalcFatSize(sectors, fatType, sectorsPerCluster, (uint)diskGeometry.BytesPerSector);
14531454

14541455
bootSector[0] = 0xEB;
14551456
bootSector[1] = 0x3C;
@@ -1459,8 +1460,7 @@ private static void WriteBPB(
14591460
"DISCUTIL"u8.CopyTo(bootSector.Slice(3, 8));
14601461

14611462
// Bytes Per Sector (512)
1462-
bootSector[11] = 0;
1463-
bootSector[12] = 2;
1463+
EndianUtilities.WriteBytesLittleEndian((ushort)diskGeometry.BytesPerSector, bootSector.Slice(11));
14641464

14651465
// Sectors Per Cluster
14661466
bootSector[13] = sectorsPerCluster;
@@ -1531,11 +1531,11 @@ private static void WriteBPB(
15311531
bootSector[511] = 0xAA;
15321532
}
15331533

1534-
private static uint CalcFatSize(uint sectors, FatType fatType, byte sectorsPerCluster)
1534+
private static uint CalcFatSize(uint sectors, FatType fatType, byte sectorsPerCluster, uint bytesPerSector)
15351535
{
15361536
var numClusters = sectors / sectorsPerCluster;
15371537
var fatBytes = numClusters * (ushort)fatType / 8;
1538-
return (fatBytes + Sizes.Sector - 1) / Sizes.Sector;
1538+
return (fatBytes + bytesPerSector - 1) / bytesPerSector;
15391539
}
15401540

15411541
private static void WriteBS(Span<byte> bootSector, bool isFloppy, uint volId, string label,
@@ -1692,7 +1692,7 @@ private void LoadRootDirectory()
16921692

16931693
private void LoadFAT()
16941694
{
1695-
Fat = new FileAllocationTable(FatVariant, _data, _bpbRsvdSecCnt, (uint)FatSize, FatCount, ActiveFat);
1695+
Fat = new FileAllocationTable(FatVariant, _data, _bpbRsvdSecCnt, (uint)FatSize, FatCount, ActiveFat, _bpbBytesPerSec);
16961696
}
16971697

16981698
private void ReadBPB()
@@ -1912,7 +1912,7 @@ public static FatFileSystem FormatFloppy(Stream stream, FloppyDiskType type, str
19121912
stream.Write(bpb);
19131913

19141914
// Write both FAT copies
1915-
var fatSize = CalcFatSize(sectors, FatType.Fat12, 1);
1915+
var fatSize = CalcFatSize(sectors, FatType.Fat12, 1, Sizes.Sector);
19161916
var fat = new byte[fatSize * Sizes.Sector];
19171917
var fatBuffer = new FatBuffer(FatType.Fat12, fat);
19181918
fatBuffer.SetNext(0, 0xFFFFFFF0);
@@ -2056,13 +2056,15 @@ public static FatFileSystem FormatPartition(
20562056
* Skip the reserved sectors
20572057
*/
20582058

2059-
stream.Position = pos + (ushort)reservedSectors * Sizes.Sector;
2059+
var bytesPerSector = diskGeometry.BytesPerSector;
2060+
2061+
stream.Position = pos + (ushort)reservedSectors * bytesPerSector;
20602062

20612063
/*
20622064
* Write both FAT copies
20632065
*/
20642066

2065-
var fat = new byte[CalcFatSize((uint)sectorCount, fatType, sectorsPerCluster) * Sizes.Sector];
2067+
var fat = new byte[CalcFatSize((uint)sectorCount, fatType, sectorsPerCluster, (uint)bytesPerSector) * bytesPerSector];
20662068
var fatBuffer = new FatBuffer(fatType, fat);
20672069
fatBuffer.SetNext(0, 0xFFFFFFF8);
20682070
fatBuffer.SetEndOfChain(1);
@@ -2083,23 +2085,23 @@ public static FatFileSystem FormatPartition(
20832085
uint rootDirSectors;
20842086
if (fatType < FatType.Fat32)
20852087
{
2086-
rootDirSectors = (uint)((maxRootEntries * 32 + Sizes.Sector - 1) / Sizes.Sector);
2088+
rootDirSectors = (uint)((maxRootEntries * 32 + bytesPerSector - 1) / bytesPerSector);
20872089
}
20882090
else
20892091
{
20902092
rootDirSectors = sectorsPerCluster;
20912093
}
20922094

2093-
var rootDir = new byte[rootDirSectors * Sizes.Sector];
2095+
var rootDir = new byte[rootDirSectors * bytesPerSector];
20942096
stream.Write(rootDir, 0, rootDir.Length);
20952097

20962098
/*
20972099
* Make sure the stream is at least as large as the partition requires.
20982100
*/
20992101

2100-
if (stream.Length < pos + sectorCount * Sizes.Sector)
2102+
if (stream.Length < pos + sectorCount * bytesPerSector)
21012103
{
2102-
stream.SetLength(pos + sectorCount * Sizes.Sector);
2104+
stream.SetLength(pos + sectorCount * bytesPerSector);
21032105
}
21042106

21052107
/*

Library/DiscUtils.Fat/FileAllocationTable.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,21 @@ namespace DiscUtils.Fat;
3030
internal class FileAllocationTable
3131
{
3232
private readonly FatBuffer _buffer;
33+
private readonly int _bytesPerSector;
3334
private readonly ushort _firstFatSector;
3435
private readonly byte _numFats;
3536
private readonly Stream _stream;
3637

3738
public FileAllocationTable(FatType type, Stream stream, ushort firstFatSector, uint fatSize, byte numFats,
38-
byte activeFat)
39+
byte activeFat, int bytesPerSector)
3940
{
4041
_stream = stream;
4142
_firstFatSector = firstFatSector;
4243
_numFats = numFats;
44+
_bytesPerSector = bytesPerSector;
4345

44-
_stream.Position = (firstFatSector + fatSize * activeFat) * Sizes.Sector;
45-
_buffer = new FatBuffer(type, _stream.ReadExactly((int)(fatSize * Sizes.Sector)));
46+
_stream.Position = (firstFatSector + fatSize * activeFat) * bytesPerSector;
47+
_buffer = new FatBuffer(type, _stream.ReadExactly((int)(fatSize * bytesPerSector)));
4648
}
4749

4850
internal static bool IsFree(uint val)
@@ -84,7 +86,7 @@ internal void Flush()
8486
{
8587
for (var i = 0; i < _numFats; ++i)
8688
{
87-
_buffer.WriteDirtyRegions(_stream, _firstFatSector * Sizes.Sector + _buffer.Size * i);
89+
_buffer.WriteDirtyRegions(_stream, _firstFatSector * _bytesPerSector + _buffer.Size * i);
8890
}
8991

9092
_buffer.ClearDirtyRegions();
@@ -94,7 +96,7 @@ internal async ValueTask FlushAsync(CancellationToken cancellationToken)
9496
{
9597
for (var i = 0; i < _numFats; ++i)
9698
{
97-
await _buffer.WriteDirtyRegionsAsync(_stream, _firstFatSector * Sizes.Sector + _buffer.Size * i, cancellationToken).ConfigureAwait(false);
99+
await _buffer.WriteDirtyRegionsAsync(_stream, _firstFatSector * _bytesPerSector + _buffer.Size * i, cancellationToken).ConfigureAwait(false);
98100
}
99101

100102
_buffer.ClearDirtyRegions();

Library/DiscUtils.Streams/Util/MathUtilities.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,16 @@ public static int Log2(int val)
135135

136136
throw new ArgumentException("Input is not a power of Two", nameof(val));
137137
}
138+
139+
public static bool IsPowerOfTwo(int bpbBytesPerSec) =>
140+
// A number is a power of two if it is greater than 0 and the bitwise AND of the number and its predecessor is 0.
141+
bpbBytesPerSec > 0 && (bpbBytesPerSec & bpbBytesPerSec - 1) == 0;
142+
143+
public static bool IsPowerOfTwo(long bpbBytesPerSec) =>
144+
// A number is a power of two if it is greater than 0 and the bitwise AND of the number and its predecessor is 0.
145+
bpbBytesPerSec > 0 && (bpbBytesPerSec & bpbBytesPerSec - 1) == 0;
146+
147+
public static bool IsPowerOfTwo(ulong bpbBytesPerSec) =>
148+
// A number is a power of two if it is greater than 0 and the bitwise AND of the number and its predecessor is 0.
149+
(bpbBytesPerSec & bpbBytesPerSec - 1) == 0;
138150
}

0 commit comments

Comments
 (0)