Skip to content

Commit

Permalink
Detect FAT cycles with Floyd's algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-visionaid committed Nov 20, 2024
1 parent aa1c1ea commit 51d899b
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 19 deletions.
21 changes: 8 additions & 13 deletions OpenMcdf/FatChainEnumerator.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;

namespace OpenMcdf;

Expand All @@ -12,12 +11,12 @@ internal sealed class FatChainEnumerator : IEnumerator<uint>
{
private readonly Fat fat;
private readonly FatEnumerator fatEnumerator;
readonly HashSet<uint> visited = new();
private uint startId;
private bool start = true;
private uint index = uint.MaxValue;
private uint current = uint.MaxValue;
private long length = -1;
private uint slow = uint.MaxValue; // Floyd's cycle-finding algorithm

public FatChainEnumerator(Fat fat, uint startSectorId)
{
Expand Down Expand Up @@ -65,7 +64,7 @@ public bool MoveNext()
index = 0;
current = startId;
start = false;
visited.Add(current);
slow = startId;
return true;
}

Expand All @@ -83,23 +82,19 @@ public bool MoveNext()
index++;
if (index >= fat.Context.SectorCount)
{
// If the index is greater than the maximum, then the chain must contain a loop
index = uint.MaxValue;
current = uint.MaxValue;
throw new FileFormatException("FAT chain index is greater than the sector count.");
}

if (visited.Contains(value))
if (index % 2 == 0 && !SectorType.IsFreeOrEndOfChain(slow))
{
// If the sector has already been visited, then the chain must contain a loop
index = uint.MaxValue;
current = uint.MaxValue;
throw new FileFormatException("FAT chain contains a loop.");
// Slow might become free or end of chain while shrinking
slow = fat[slow];
if (slow == value)
throw new FileFormatException("FAT chain contains a loop.");
}

if (BitOperations.IsPow2(index))
visited.Add(value);

current = value;
return true;
}
Expand Down Expand Up @@ -246,7 +241,7 @@ public void Reset(uint startSectorId)
start = true;
index = uint.MaxValue;
current = uint.MaxValue;
visited.Clear();
slow = uint.MaxValue;
}

[ExcludeFromCodeCoverage]
Expand Down
6 changes: 0 additions & 6 deletions OpenMcdf/System/BitOperations.cs

This file was deleted.

0 comments on commit 51d899b

Please sign in to comment.