Skip to content

Commit

Permalink
Trim non-transacted streams on flush
Browse files Browse the repository at this point in the history
  • Loading branch information
Numpsy authored and jeremy-visionaid committed Dec 5, 2024
1 parent cc31d17 commit 0a740bb
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
24 changes: 24 additions & 0 deletions OpenMcdf.Tests/RootStorageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,28 @@ public void SwitchTransactedStream(Version version, int subStorageCount)
rootStorage.OpenStorage($"Test{i}");
}
}

[TestMethod]
[DataRow(false)]
[DataRow(true)]
public void DeleteTrimsBaseStream(bool consolidate)
{
using var rootStorage = RootStorage.CreateInMemory(Version.V3, StorageModeFlags.LeaveOpen);
using (CfbStream stream = rootStorage.CreateStream("Test"))
{
byte[] buffer = TestData.CreateByteArray(4096);
stream.Write(buffer, 0, buffer.Length);
}

rootStorage.Flush(consolidate);

long originalLength = rootStorage.BaseStream.Length;

rootStorage.Delete("Test");
rootStorage.Flush(consolidate);

long newLength = rootStorage.BaseStream.Length;

Assert.IsTrue(originalLength > newLength);
}
}
12 changes: 12 additions & 0 deletions OpenMcdf/Fat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ public uint Add(FatEnumerator fatEnumerator, uint startIndex)
return entry.Index;
}

public Sector GetLastUsedSector()
{
uint lastUsedSectorIndex = uint.MaxValue;
foreach (FatEntry entry in this)
{
if (!entry.IsFree)
lastUsedSectorIndex = entry.Index;
}

return new(lastUsedSectorIndex, Context.SectorSize);
}

public IEnumerator<FatEntry> GetEnumerator() => new FatEnumerator(Context.Fat);

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
Expand Down
19 changes: 12 additions & 7 deletions OpenMcdf/RootContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ public FatStream MiniStream

public uint SectorCount => (uint)Math.Max(0, (Length - SectorSize) / SectorSize); // TODO: Check

bool isDirty;

public RootContext(RootContextSite rootContextSite, Stream stream, Version version, IOContextFlags contextFlags = IOContextFlags.None)
: base(rootContextSite)
{
Expand Down Expand Up @@ -178,20 +176,27 @@ public void Flush()
{
Fat.Flush();

if (isDirty && writer is not null && transactedStream is null)
if (writer is not null && transactedStream is null)
{
// Ensure the stream is as long as expected
BaseStream.SetLength(Length);
TrimBaseStream();
WriteHeader();
isDirty = false;
}
}

public void ExtendStreamLength(long length)
{
if (Length < length)
Length = length;
isDirty = true;
}

void TrimBaseStream()
{
Sector lastUsedSector = Fat.GetLastUsedSector();
if (!lastUsedSector.IsValid)
throw new FileFormatException("Last used sector is invalid");

Length = lastUsedSector.EndPosition;
BaseStream.SetLength(Length);
}

public void WriteHeader()
Expand Down

0 comments on commit 0a740bb

Please sign in to comment.