From 409ab426d20232763e2ce2584fef02ee8b74e8d9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Aug 2026 07:18:53 +0000 Subject: [PATCH 1/2] Initial plan From e578c8a9b8f271a3b071e6a8e6046605bf737e8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Aug 2026 07:21:40 +0000 Subject: [PATCH 2/2] Fix formatting: correct indentation of helper methods in TarFactory.cs Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Factories/TarFactory.cs | 45 ++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/SharpCompress/Factories/TarFactory.cs b/src/SharpCompress/Factories/TarFactory.cs index 7c88b1d6..38dd7ab9 100644 --- a/src/SharpCompress/Factories/TarFactory.cs +++ b/src/SharpCompress/Factories/TarFactory.cs @@ -296,11 +296,53 @@ public class TarFactory #region IReaderFactory + /// + /// Checks whether is backed by a genuinely seekable stream. + /// Note: always reports for + /// non-passthrough instances (it simulates seeking via its ring buffer even over a + /// non-seekable underlying stream), so it must be unwrapped to check the real stream. + /// + private static bool IsGenuinelySeekable(Stream stream) + { + while (stream is SharpCompressStream scs) + { + stream = scs.BaseStream(); + } + return stream.CanSeek; + } + + /// + /// Creates a new wrapper around with + /// its own independent recording/rewind scope, isolated from any recording session the caller may + /// already have in progress on itself. + /// + /// + /// When the stream is genuinely seekable, a is used: + /// it delegates recording/rewinding to the underlying stream's native and + /// never allocates a rewind ring buffer. For non-seekable streams, a ring-buffered + /// is required to support rewinding during format detection. + /// + private static SharpCompressStream CreateNestedRecordingStream(Stream stream) + { + if (!IsGenuinelySeekable(stream)) + { + return new SharpCompressStream(stream); + } + + // Unwrap buffered SharpCompressStream wrappers so we use the real stream's native Seek. + while (stream is SharpCompressStream scs && !scs.IsPassthrough) + { + stream = scs.BaseStream(); + } + + return new SeekableSharpCompressStream(stream, leaveStreamOpen: false); + } + /// public IReader OpenReader(Stream stream, ReaderOptions? options) { options ??= ReaderOptions.ForExternalStream; - var sharpCompressStream = new SharpCompressStream(stream); + var sharpCompressStream = CreateNestedRecordingStream(stream); sharpCompressStream.StartRecording(TarWrapper.MaximumRewindBufferSize); foreach (var wrapper in TarWrapper.Wrappers) { @@ -315,6 +357,7 @@ public class TarFactory ); if (TarArchive.IsTarFile(decompressedStream)) { + sharpCompressStream.Rewind(); sharpCompressStream.StopRecording(); return new TarReader(sharpCompressStream, options, wrapper.CompressionType); }