From 2a68ec725704ca82a491d12a1fa4f79c23628ea6 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sat, 10 Oct 2026 15:40:35 +0100 Subject: [PATCH] Read ARC entry headers fully on fragmented streams --- .../Common/Arc/ArcEntryHeader.cs | 8 ++---- .../Arc/ArcHeaderReadTests.cs | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 tests/SharpCompress.Test/Arc/ArcHeaderReadTests.cs diff --git a/src/SharpCompress/Common/Arc/ArcEntryHeader.cs b/src/SharpCompress/Common/Arc/ArcEntryHeader.cs index 983b1b78..1fb91983 100644 --- a/src/SharpCompress/Common/Arc/ArcEntryHeader.cs +++ b/src/SharpCompress/Common/Arc/ArcEntryHeader.cs @@ -26,7 +26,7 @@ public class ArcEntryHeader public ArcEntryHeader? ReadHeader(Stream stream) { byte[] headerBytes = new byte[29]; - if (stream.Read(headerBytes, 0, headerBytes.Length) != headerBytes.Length) + if (!stream.ReadFully(headerBytes)) { return null; } @@ -40,11 +40,7 @@ public class ArcEntryHeader ) { byte[] headerBytes = new byte[29]; - if ( - await stream - .ReadAsync(headerBytes, 0, headerBytes.Length, cancellationToken) - .ConfigureAwait(false) != headerBytes.Length - ) + if (!await stream.ReadFullyAsync(headerBytes, cancellationToken).ConfigureAwait(false)) { return null; } diff --git a/tests/SharpCompress.Test/Arc/ArcHeaderReadTests.cs b/tests/SharpCompress.Test/Arc/ArcHeaderReadTests.cs new file mode 100644 index 00000000..147ebc42 --- /dev/null +++ b/tests/SharpCompress.Test/Arc/ArcHeaderReadTests.cs @@ -0,0 +1,26 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Common.Arc; +using SharpCompress.Test.Mocks; +using Xunit; + +namespace SharpCompress.Test.Arc; + +public class ArcHeaderReadTests +{ + [Fact] + public async Task Arc_Header_Allows_Partial_Reads() + { + var header = new byte[29]; + header[0] = 0x1A; + header[1] = 2; + header[2] = (byte)'x'; + using var sync = new ShortReadStream(new MemoryStream(header)); + using var asyncInput = new ShortReadStream(new MemoryStream(header)); + var parser = new ArcEntryHeader(new ArchiveEncoding()); + Assert.Equal("x", parser.ReadHeader(sync)!.Name); + Assert.Equal("x", (await parser.ReadHeaderAsync(asyncInput, CancellationToken.None))!.Name); + } +}