From fb0cd47bb0cee5dfee645459c8fcaeba6b1d9d9b Mon Sep 17 00:00:00 2001 From: drone1400 <93078773+drone1400@users.noreply.github.com> Date: Fri, 30 Oct 2026 11:48:10 +0200 Subject: [PATCH] Add tests for long USTAR names split at a directory separator When an entry name is longer than the 100 byte USTAR name field, TarHeader splits it into the 155 byte prefix field and the name field at a directory separator. The existing tests only covered short paths and long names without any separator. Add sync and async tests that write a 186 byte path (with '/' and '\' separators as input) using the USTAR format and read it back. On Windows these tests fail with InvalidFormatException ("Directory separator not found!"), which the next commit fixes. They pass on Linux and macOS. Co-Authored-By: Claude Opus 5.5 --- .../Tar/TarWriterAsyncTests.cs | 28 +++++++++++++++++++ .../SharpCompress.Test/Tar/TarWriterTests.cs | 28 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tests/SharpCompress.Test/Tar/TarWriterAsyncTests.cs b/tests/SharpCompress.Test/Tar/TarWriterAsyncTests.cs index 31fa98fa..a9e9d089 100644 --- a/tests/SharpCompress.Test/Tar/TarWriterAsyncTests.cs +++ b/tests/SharpCompress.Test/Tar/TarWriterAsyncTests.cs @@ -124,6 +124,34 @@ public class TarWriterAsyncTests : WriterTests ); } + [Theory] + [InlineData('/')] + [InlineData('\\')] + public async ValueTask Tar_Ustar_HeaderFormat_WritesLongPathUsingPrefix_Async(char separator) + { + // 186 bytes: too long for the 100 byte name field, but splittable into prefix + name + var longName = + new string('a', 60) + + separator + + new string('b', 60) + + separator + + new string('c', 60) + + ".txt"; + + using var stream = new MemoryStream(); + var options = new TarWriterOptions(CompressionType.None, true, TarHeaderWriteFormat.USTAR); + await using (var writer = new TarWriter(new AsyncOnlyStream(stream), options)) + using (var content = new MemoryStream(Encoding.UTF8.GetBytes("hello"))) + { + await writer.WriteAsync(longName, content, null); + } + + stream.Position = 0; + using var archive = TarArchive.OpenArchive(stream); + Assert.Single(archive.Entries); + Assert.Equal(longName.Replace('\\', '/'), archive.Entries.Single().Key); + } + [Fact] public async ValueTask Tar_GnuLongLink_HeaderFormat_WritesLongPath_Async() { diff --git a/tests/SharpCompress.Test/Tar/TarWriterTests.cs b/tests/SharpCompress.Test/Tar/TarWriterTests.cs index 45660128..873ff74a 100644 --- a/tests/SharpCompress.Test/Tar/TarWriterTests.cs +++ b/tests/SharpCompress.Test/Tar/TarWriterTests.cs @@ -110,6 +110,34 @@ public class TarWriterTests : WriterTests Assert.Throws(() => writer.Write(longName, content, null)); } + [Theory] + [InlineData('/')] + [InlineData('\\')] + public void Tar_Ustar_HeaderFormat_WritesLongPathUsingPrefix(char separator) + { + // 186 bytes: too long for the 100 byte name field, but splittable into prefix + name + var longName = + new string('a', 60) + + separator + + new string('b', 60) + + separator + + new string('c', 60) + + ".txt"; + + using var stream = new MemoryStream(); + var options = new TarWriterOptions(CompressionType.None, true, TarHeaderWriteFormat.USTAR); + using (var writer = new TarWriter(stream, options)) + using (var content = new MemoryStream(Encoding.UTF8.GetBytes("hello"))) + { + writer.Write(longName, content, null); + } + + stream.Position = 0; + using var archive = TarArchive.OpenArchive(stream); + Assert.Single(archive.Entries); + Assert.Equal(longName.Replace('\\', '/'), archive.Entries.Single().Key); + } + [Fact] public void Tar_GnuLongLink_HeaderFormat_WritesLongPath() {