diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs index 898daf1e6c3ed7..946f668dc4a346 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHelpers.cs @@ -202,19 +202,18 @@ internal static TarEntryType GetCorrectTypeFlagForFormat(TarEntryFormat format, /// Parses a byte span that represents an ASCII string containing a number in octal base. internal static T ParseOctal(ReadOnlySpan buffer) where T : struct, INumber { - buffer = TrimEndingNullsAndSpaces(buffer); - T octalFactor = T.CreateTruncating(8u); T value = T.Zero; - foreach (byte b in buffer) + + // skip leading non-octal bytes + int offset = 0; + for (; offset < buffer.Length && (buffer[offset] < (byte)'0' || buffer[offset] > (byte)'7'); ++offset); + + foreach (byte b in buffer.Slice(offset)) { - uint digit = (uint)(b - '0'); - if (digit >= 8) - { - ThrowInvalidNumber(); - } + if (b < (byte)'0' || b > (byte)'7') break; - value = checked((value * octalFactor) + T.CreateTruncating(digit)); + value = checked((value * octalFactor) + T.CreateTruncating((uint)(b - '0'))); } return value; diff --git a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs index 5e35c12c3aaac9..75e3e27ef9e0fb 100644 --- a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; @@ -125,28 +125,38 @@ public void Read_Archive_LongFileName_Over100_Under255(TarEntryFormat format, Te public void Read_Archive_LongPath_Over255(TarEntryFormat format, TestTarFormat testFormat) => Read_Archive_LongPath_Over255_Internal(format, testFormat); - [Fact] - public void Read_NodeTarArchives_Successfully() + public static IEnumerable GetTarFiles(string subset) { - string nodeTarPath = Path.Join(Directory.GetCurrentDirectory(), "tar", "node-tar"); - foreach (string file in Directory.EnumerateFiles(nodeTarPath, "*.tar", SearchOption.AllDirectories)) + string path = Path.Join(Directory.GetCurrentDirectory(), "tar", subset); + foreach (string file in Directory.EnumerateFiles(path, "*.tar", SearchOption.AllDirectories)) { - using FileStream sourceStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); - using var reader = new TarReader(sourceStream); + yield return new object[] { file }; + } + } - TarEntry? entry = null; - while (true) - { - Exception ex = Record.Exception(() => entry = reader.GetNextEntry()); - Assert.Null(ex); + [Theory] + [MemberData(nameof(GetTarFiles), "node-tar")] + [MemberData(nameof(GetTarFiles), "tar-rs")] + public void Read_TestArchives_Successfully(string file) + { + using FileStream sourceStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); + using var reader = new TarReader(sourceStream); - if (entry is null) break; + TarEntry? entry = null; + while ((entry = reader.GetNextEntry()) != null) + { + Assert.NotNull(entry.Name); + Assert.True(Enum.IsDefined(entry.EntryType)); + Assert.True(Enum.IsDefined(entry.Format)); - ex = Record.Exception(() => entry.Name); - Assert.Null(ex); + if (entry.EntryType == TarEntryType.Directory) + continue; - ex = Record.Exception(() => entry.Length); - Assert.Null(ex); + var ds = entry.DataStream; + if (ds != null && ds.Length > 0) + { + using var memoryStream = new MemoryStream(); + ds.CopyTo(memoryStream); } } } diff --git a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs index bad9bf8fa179bf..a1ab5e9ffdc521 100644 --- a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntry.Tests.cs @@ -20,19 +20,6 @@ public void MalformedArchive_TooSmall() Assert.Throws(() => reader.GetNextEntry()); } - [Fact] - public void MalformedArchive_HeaderSize() - { - using MemoryStream malformed = new MemoryStream(); - byte[] buffer = new byte[512]; // Minimum length of any header - Array.Fill(buffer, 0x1); - malformed.Write(buffer); - malformed.Seek(0, SeekOrigin.Begin); - - using TarReader reader = new TarReader(malformed); - Assert.Throws(() => reader.GetNextEntry()); - } - [Fact] public void EmptyArchive() { diff --git a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntryAsync.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntryAsync.Tests.cs index 77ddf1f1320621..fa21cad647dc33 100644 --- a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntryAsync.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.GetNextEntryAsync.Tests.cs @@ -39,23 +39,6 @@ public async Task MalformedArchive_TooSmall_Async() } } - [Fact] - public async Task MalformedArchive_HeaderSize_Async() - { - await using (MemoryStream malformed = new MemoryStream()) - { - byte[] buffer = new byte[512]; // Minimum length of any header - Array.Fill(buffer, 0x1); - malformed.Write(buffer); - malformed.Seek(0, SeekOrigin.Begin); - - await using (TarReader reader = new TarReader(malformed)) - { - await Assert.ThrowsAsync(async () => await reader.GetNextEntryAsync()); - } - } - } - [Fact] public async Task EmptyArchive_Async() {