mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
Preserve legacy 7z property size compatibility during preflight
This commit is contained in:
@@ -338,7 +338,11 @@ internal sealed partial class ArchiveReader
|
||||
}
|
||||
|
||||
var numFiles = ReadNum();
|
||||
ValidateFileCount(numFiles, unpackSizes.Count);
|
||||
ValidateFileCount(
|
||||
numFiles,
|
||||
unpackSizes.Count,
|
||||
db._majorVersion > 0 || db._minorVersion > 2
|
||||
);
|
||||
db._files = new List<CFileItem>(numFiles);
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
|
||||
@@ -714,8 +714,18 @@ internal partial class ArchiveReader
|
||||
return (int)size;
|
||||
}
|
||||
|
||||
private void ValidateFileCount(int numFiles, int numStreams)
|
||||
private void ValidateFileCount(int numFiles, int numStreams, bool checkRecordsSize)
|
||||
{
|
||||
if (!checkRecordsSize)
|
||||
{
|
||||
// Before 0.3, known properties may have inaccurate sizes, so walking
|
||||
// them by their declared lengths would disagree with the real parser.
|
||||
// Bound the allocation by the minimum possible empty-stream bitmap;
|
||||
// ReadBitVector separately bounds the actual bitmap at its read position.
|
||||
var minimumEmptyStreams = Math.Max(0L, (long)numFiles - numStreams);
|
||||
_currentReader.RequireBytes((minimumEmptyStreams + 7) / 8);
|
||||
return;
|
||||
}
|
||||
// Nonempty files correspond to already parsed substreams. Empty files
|
||||
// require one bit each in kEmptyStream, not one byte per file. Preflight
|
||||
// that property before allocating CFileItem objects or implicit vectors.
|
||||
@@ -914,7 +924,11 @@ internal partial class ArchiveReader
|
||||
}
|
||||
|
||||
var numFiles = ReadNum();
|
||||
ValidateFileCount(numFiles, unpackSizes.Count);
|
||||
ValidateFileCount(
|
||||
numFiles,
|
||||
unpackSizes.Count,
|
||||
db._majorVersion > 0 || db._minorVersion > 2
|
||||
);
|
||||
db._files = new List<CFileItem>(numFiles);
|
||||
for (var i = 0; i < numFiles; i++)
|
||||
{
|
||||
|
||||
@@ -356,6 +356,104 @@ public class SevenZipHeaderAllocationTests
|
||||
Assert.True(stream.CanRead);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2, 0, false)]
|
||||
[InlineData(2, 0, true)]
|
||||
[InlineData(2, 127, false)]
|
||||
[InlineData(2, 127, true)]
|
||||
[InlineData(3, 0, false)]
|
||||
[InlineData(3, 0, true)]
|
||||
public async Task SevenZipArchive_Property_Size_Validation_Is_Version_Aware(
|
||||
byte minorVersion,
|
||||
byte declaredSize,
|
||||
bool useAsync
|
||||
)
|
||||
{
|
||||
// Both known properties have deliberately inaccurate sizes, including
|
||||
// a name preceding the empty-stream bitmap.
|
||||
using var stream = CreateArchive([
|
||||
1,
|
||||
5,
|
||||
1,
|
||||
17,
|
||||
declaredSize,
|
||||
0,
|
||||
(byte)'x',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
14,
|
||||
declaredSize,
|
||||
0x80,
|
||||
0,
|
||||
0,
|
||||
]);
|
||||
stream.GetBuffer()[7] = minorVersion;
|
||||
if (useAsync)
|
||||
{
|
||||
using var asyncStream = new AsyncOnlyStream(stream, disposeStream: false);
|
||||
await using var archive = await ArchiveFactory.OpenAsyncArchive(
|
||||
asyncStream,
|
||||
cancellationToken: CancellationToken.None
|
||||
);
|
||||
if (minorVersion > 2)
|
||||
{
|
||||
await Assert.ThrowsAnyAsync<SharpCompressException>(async () =>
|
||||
await archive.EntriesAsync.ToListAsync(CancellationToken.None)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entry = Assert.Single(
|
||||
await archive.EntriesAsync.ToListAsync(CancellationToken.None)
|
||||
);
|
||||
Assert.True(entry.IsDirectory);
|
||||
Assert.Equal("x", entry.Key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using var archive = ArchiveFactory.OpenArchive(stream);
|
||||
if (minorVersion > 2)
|
||||
{
|
||||
Assert.ThrowsAny<SharpCompressException>(() => archive.Entries.ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
var entry = Assert.Single(archive.Entries);
|
||||
Assert.True(entry.IsDirectory);
|
||||
Assert.Equal("x", entry.Key);
|
||||
}
|
||||
}
|
||||
Assert.True(stream.CanRead);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task SevenZipArchive_Legacy_File_Count_Is_Bounded_By_Available_Metadata(
|
||||
bool useAsync
|
||||
)
|
||||
{
|
||||
using var stream = CreateArchive(Join([1, 5], Number(100_000), [14, 0, 0x80, 0]));
|
||||
stream.GetBuffer()[7] = 2;
|
||||
if (useAsync)
|
||||
{
|
||||
await using var archive = await ArchiveFactory.OpenAsyncArchive(
|
||||
stream,
|
||||
cancellationToken: CancellationToken.None
|
||||
);
|
||||
await Assert.ThrowsAsync<IncompleteArchiveException>(async () =>
|
||||
await archive.EntriesAsync.ToListAsync(CancellationToken.None)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var archive = ArchiveFactory.OpenArchive(stream);
|
||||
Assert.Throws<IncompleteArchiveException>(() => archive.Entries.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] MetadataHeader(
|
||||
bool encoded,
|
||||
ulong unpackSize,
|
||||
|
||||
Reference in New Issue
Block a user