From 52c472f89bd3462b9af9d5647e3f87b40a3e692c Mon Sep 17 00:00:00 2001 From: David Cantu Date: Fri, 9 Sep 2022 08:54:20 -0700 Subject: [PATCH 1/5] Fix buffer too small error on prefix --- .../src/System/Formats/Tar/TarHeader.Write.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs index e1166a066814b3..7234482d3d4820 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs @@ -374,12 +374,10 @@ private int WritePosixName(Span buffer) if (_name.Length > FieldLengths.Name) { - int prefixBytesLength = Math.Min(_name.Length - FieldLengths.Name, FieldLengths.Name); - Span remaining = prefixBytesLength <= 256 ? - stackalloc byte[prefixBytesLength] : - new byte[prefixBytesLength]; - - int encoded = Encoding.ASCII.GetBytes(_name.AsSpan(FieldLengths.Name), remaining); + int prefixBytesLength = Math.Min(_name.Length - FieldLengths.Name, FieldLengths.Prefix); + Debug.Assert(prefixBytesLength <= 256); + Span remaining = stackalloc byte[prefixBytesLength]; + int encoded = Encoding.ASCII.GetBytes(_name.AsSpan(FieldLengths.Name, prefixBytesLength), remaining); Debug.Assert(encoded == remaining.Length); checksum += WriteLeftAlignedBytesAndGetChecksum(remaining, buffer.Slice(FieldLocations.Prefix, FieldLengths.Prefix)); From 862b3c432bdd5da0421094a0ed6afa1e96242c84 Mon Sep 17 00:00:00 2001 From: David Cantu Date: Fri, 9 Sep 2022 08:54:57 -0700 Subject: [PATCH 2/5] Add test --- .../TarWriter/TarWriter.WriteEntry.Tests.cs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs index b0c78298f2bb01..4b2f7ac6b46772 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs @@ -299,5 +299,62 @@ public void WriteTimestampsBeyondOctalLimit(TarEntryFormat format) } } } + + [Theory] + [InlineData(TarEntryFormat.V7)] + // On reading, ustar just combines prefix(155) + '/' + name(100), which may be wrong but that's how it currently is. + // On writing, it writes the first 100 chars of entryName on name and the next 155 on prefix, so it is flipping the name+prefix on reading. + //[InlineData(TarEntryFormat.Ustar)] + [InlineData(TarEntryFormat.Pax)] + [InlineData(TarEntryFormat.Gnu)] + public void WriteLongName(TarEntryFormat format) + { + string maxPathComponent = new string('a', 255); + WriteLongNameCore(format, maxPathComponent); + + maxPathComponent = new string('a', 90) + new string('b', 165); + WriteLongNameCore(format, maxPathComponent); + + maxPathComponent = new string('a', 165) + new string('b', 90); + WriteLongNameCore(format, maxPathComponent); + } + + private void WriteLongNameCore(TarEntryFormat format, string maxPathComponent) + { + Assert.Equal(255, maxPathComponent.Length); + + var ms = new MemoryStream(); + using (var writer = new TarWriter(ms, true)) + { + TarEntryType entryType = format == TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile; + var entry1 = InvokeTarEntryCreationConstructor(format, entryType, maxPathComponent); + writer.WriteEntry(entry1); + + var entry2 = InvokeTarEntryCreationConstructor(format, entryType, Path.Join(maxPathComponent, maxPathComponent)); + writer.WriteEntry(entry2); + } + + ms.Position = 0; + using var reader = new TarReader(ms); + + TarEntry readEntry = reader.GetNextEntry(); + string expectedName = GetExpectedNameForFormat(format, maxPathComponent); + Assert.Equal(expectedName, readEntry.Name); + + readEntry = reader.GetNextEntry(); + expectedName = GetExpectedNameForFormat(format, Path.Join(maxPathComponent, maxPathComponent)); + Assert.Equal(expectedName, readEntry.Name); + + Assert.Null(reader.GetNextEntry()); + + string GetExpectedNameForFormat(TarEntryFormat format, string expectedName) + { + if (format is TarEntryFormat.V7) // V7 truncates names at 100 characters. + { + return expectedName.Substring(0, 100); + } + return expectedName; + } + } } } From 95512e3648e255c8308a647f61bd2adb71921b9e Mon Sep 17 00:00:00 2001 From: David Cantu Date: Fri, 9 Sep 2022 09:03:53 -0700 Subject: [PATCH 3/5] Remove var usage --- .../TarWriter/TarWriter.WriteEntry.Tests.cs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs index 4b2f7ac6b46772..d7ffed3da87c99 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs @@ -323,27 +323,28 @@ private void WriteLongNameCore(TarEntryFormat format, string maxPathComponent) { Assert.Equal(255, maxPathComponent.Length); - var ms = new MemoryStream(); - using (var writer = new TarWriter(ms, true)) + TarEntry entry; + MemoryStream ms = new(); + using (TarWriter writer = new(ms, true)) { TarEntryType entryType = format == TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile; - var entry1 = InvokeTarEntryCreationConstructor(format, entryType, maxPathComponent); - writer.WriteEntry(entry1); + entry = InvokeTarEntryCreationConstructor(format, entryType, maxPathComponent); + writer.WriteEntry(entry); - var entry2 = InvokeTarEntryCreationConstructor(format, entryType, Path.Join(maxPathComponent, maxPathComponent)); - writer.WriteEntry(entry2); + entry = InvokeTarEntryCreationConstructor(format, entryType, Path.Join(maxPathComponent, maxPathComponent)); + writer.WriteEntry(entry); } ms.Position = 0; - using var reader = new TarReader(ms); + using TarReader reader = new(ms); - TarEntry readEntry = reader.GetNextEntry(); + entry = reader.GetNextEntry(); string expectedName = GetExpectedNameForFormat(format, maxPathComponent); - Assert.Equal(expectedName, readEntry.Name); + Assert.Equal(expectedName, entry.Name); - readEntry = reader.GetNextEntry(); + entry = reader.GetNextEntry(); expectedName = GetExpectedNameForFormat(format, Path.Join(maxPathComponent, maxPathComponent)); - Assert.Equal(expectedName, readEntry.Name); + Assert.Equal(expectedName, entry.Name); Assert.Null(reader.GetNextEntry()); From e8983baeafb7179fd40680de39b3e4261e8eab39 Mon Sep 17 00:00:00 2001 From: David Cantu Date: Fri, 9 Sep 2022 09:16:14 -0700 Subject: [PATCH 4/5] Remove assert --- .../System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs index 7234482d3d4820..43fe79ce7dc0a6 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs @@ -375,7 +375,6 @@ private int WritePosixName(Span buffer) if (_name.Length > FieldLengths.Name) { int prefixBytesLength = Math.Min(_name.Length - FieldLengths.Name, FieldLengths.Prefix); - Debug.Assert(prefixBytesLength <= 256); Span remaining = stackalloc byte[prefixBytesLength]; int encoded = Encoding.ASCII.GetBytes(_name.AsSpan(FieldLengths.Name, prefixBytesLength), remaining); Debug.Assert(encoded == remaining.Length); From de0c26910a65f65f28b008d8463a51a7326b3b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Fri, 9 Sep 2022 11:24:05 -0700 Subject: [PATCH 5/5] Update src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs --- .../tests/TarWriter/TarWriter.WriteEntry.Tests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs index d7ffed3da87c99..9c2aa572c344c4 100644 --- a/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.WriteEntry.Tests.cs @@ -302,9 +302,7 @@ public void WriteTimestampsBeyondOctalLimit(TarEntryFormat format) [Theory] [InlineData(TarEntryFormat.V7)] - // On reading, ustar just combines prefix(155) + '/' + name(100), which may be wrong but that's how it currently is. - // On writing, it writes the first 100 chars of entryName on name and the next 155 on prefix, so it is flipping the name+prefix on reading. - //[InlineData(TarEntryFormat.Ustar)] + // [InlineData(TarEntryFormat.Ustar)] https://github.com/dotnet/runtime/issues/75360 [InlineData(TarEntryFormat.Pax)] [InlineData(TarEntryFormat.Gnu)] public void WriteLongName(TarEntryFormat format)