Look for the Wise overlay header before opening the file again (#103)

ExtractWiseOverlay (and ExtractWise for NE) opened a second stream on
the executable for multi-part Wise installers before checking for a
Wise overlay header at all. For any other executable that stream was
never closed, so the file stayed open until the stream was finalized.
On Windows such a file cannot be deleted, so an extraction folder that
contains it is left behind in TEMP.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
gmipf
2026-10-19 15:50:21 +02:00
committed by GitHub
parent f6ade446c6
commit 29b9d27c33
3 changed files with 38 additions and 12 deletions

View File

@@ -56,5 +56,32 @@ namespace SabreTools.Wrappers.Test
var actual = PortableExecutable.Create(data);
Assert.Null(actual);
}
[Fact]
public void ExtractWiseOverlay_NotWise_FileNotKeptOpen()
{
// Any executable that is not a Wise installer, here a copy of this test assembly
string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
string outputDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
File.Copy(typeof(PortableExecutableTests).Assembly.Location, path);
try
{
using (var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var pe = PortableExecutable.Create(stream);
Assert.NotNull(pe);
Assert.False(pe.ExtractWiseOverlay(outputDirectory, includeDebug: false));
}
// Opening the file exclusively fails while another handle to it is still open
using var exclusive = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
Assert.True(exclusive.CanRead);
}
finally
{
File.Delete(path);
}
}
}
}

View File

@@ -208,6 +208,11 @@ namespace SabreTools.Wrappers
/// <returns>True if extraction succeeded, false otherwise</returns>
public bool ExtractWise(string outputDirectory, bool includeDebug)
{
// Try to find the overlay header
long offset = FindWiseOverlayHeader();
if (offset <= 0 || offset >= Length)
return false;
// Get the source data for reading
Stream source = _dataSource;
if (Filename is not null)
@@ -217,13 +222,7 @@ namespace SabreTools.Wrappers
source = temp;
}
// Try to find the overlay header
long offset = FindWiseOverlayHeader();
if (offset > 0 && offset < Length)
return ExtractWiseOverlay(outputDirectory, includeDebug, source, offset);
// Everything else could not extract
return false;
return ExtractWiseOverlay(outputDirectory, includeDebug, source, offset);
}
/// <summary>

View File

@@ -638,6 +638,11 @@ namespace SabreTools.Wrappers
/// <returns>True if extraction succeeded, false otherwise</returns>
public bool ExtractWiseOverlay(string outputDirectory, bool includeDebug)
{
// Try to find the overlay header
long offset = FindWiseOverlayHeader();
if (offset <= 0 || offset > Length)
return false;
// Get the source data for reading
Stream source = _dataSource;
if (Filename is not null)
@@ -647,11 +652,6 @@ namespace SabreTools.Wrappers
source = temp;
}
// Try to find the overlay header
long offset = FindWiseOverlayHeader();
if (offset <= 0 || offset > Length)
return false;
// Seek to the overlay and parse
source.SeekIfPossible(offset, SeekOrigin.Begin);
var header = WiseOverlayHeader.Create(source);