From fcd5a1e79144f407de210eaae0a90c94441b3854 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Mon, 22 Aug 2022 19:44:58 +0300 Subject: [PATCH 1/3] Allow spaces in octal attributes --- .../src/System/Formats/Tar/TarHelpers.cs | 2 ++ .../tests/TarReader/TarReader.File.Tests.cs | 35 +++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) 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..1576d3bdf2dd1f 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 @@ -208,6 +208,8 @@ internal static T ParseOctal(ReadOnlySpan buffer) where T : struct, INu T value = T.Zero; foreach (byte b in buffer) { + if (b == (byte)' ') continue; // skip space + uint digit = (uint)(b - '0'); if (digit >= 8) { 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..a63491445485a9 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,33 @@ 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() + [Theory] + [InlineData("node-tar")] + [InlineData("tar-rs")] + public void Read_TestArchives_Successfully(string subset) { - string nodeTarPath = Path.Join(Directory.GetCurrentDirectory(), "tar", "node-tar"); + string nodeTarPath = Path.Join(Directory.GetCurrentDirectory(), "tar", subset); foreach (string file in Directory.EnumerateFiles(nodeTarPath, "*.tar", SearchOption.AllDirectories)) { using FileStream sourceStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); using var reader = new TarReader(sourceStream); TarEntry? entry = null; - while (true) + while ((entry = reader.GetNextEntry()) != null) { - Exception ex = Record.Exception(() => entry = reader.GetNextEntry()); - Assert.Null(ex); - - if (entry is null) break; - - ex = Record.Exception(() => entry.Name); - Assert.Null(ex); - - ex = Record.Exception(() => entry.Length); - Assert.Null(ex); + Assert.NotNull(entry.Name); + Assert.True(Enum.IsDefined(entry.EntryType)); + Assert.True(Enum.IsDefined(entry.Format)); + + if (entry.EntryType == TarEntryType.Directory) + continue; + + var ds = entry.DataStream; + if (ds != null && ds.Length > 0) + { + using var memoryStream = new MemoryStream(); + ds.CopyTo(memoryStream); + } } } } From 90c306b73cee789b1019a0a63e9184c494325214 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Mon, 22 Aug 2022 22:53:35 +0300 Subject: [PATCH 2/3] Align behavior with libarchive --- .../src/System/Formats/Tar/TarHelpers.cs | 19 ++++++++----------- .../TarReader/TarReader.GetNextEntry.Tests.cs | 13 ------------- .../TarReader.GetNextEntryAsync.Tests.cs | 17 ----------------- 3 files changed, 8 insertions(+), 41 deletions(-) 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 1576d3bdf2dd1f..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,21 +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) - { - if (b == (byte)' ') continue; // skip space - uint digit = (uint)(b - '0'); - if (digit >= 8) - { - ThrowInvalidNumber(); - } + // 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)) + { + 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.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() { From 96a88cc352ad3acfe78518732ddbee4f40726d6c Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Tue, 23 Aug 2022 03:54:59 +0300 Subject: [PATCH 3/3] Use MemberData in theory test --- .../tests/TarReader/TarReader.File.Tests.cs | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) 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 a63491445485a9..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 @@ -125,33 +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); + public static IEnumerable GetTarFiles(string subset) + { + string path = Path.Join(Directory.GetCurrentDirectory(), "tar", subset); + foreach (string file in Directory.EnumerateFiles(path, "*.tar", SearchOption.AllDirectories)) + { + yield return new object[] { file }; + } + } + [Theory] - [InlineData("node-tar")] - [InlineData("tar-rs")] - public void Read_TestArchives_Successfully(string subset) + [MemberData(nameof(GetTarFiles), "node-tar")] + [MemberData(nameof(GetTarFiles), "tar-rs")] + public void Read_TestArchives_Successfully(string file) { - string nodeTarPath = Path.Join(Directory.GetCurrentDirectory(), "tar", subset); - foreach (string file in Directory.EnumerateFiles(nodeTarPath, "*.tar", SearchOption.AllDirectories)) + using FileStream sourceStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); + using var reader = new TarReader(sourceStream); + + TarEntry? entry = null; + while ((entry = reader.GetNextEntry()) != null) { - using FileStream sourceStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read); - using var reader = new TarReader(sourceStream); + Assert.NotNull(entry.Name); + Assert.True(Enum.IsDefined(entry.EntryType)); + Assert.True(Enum.IsDefined(entry.Format)); + + if (entry.EntryType == TarEntryType.Directory) + continue; - TarEntry? entry = null; - while ((entry = reader.GetNextEntry()) != null) + var ds = entry.DataStream; + if (ds != null && ds.Length > 0) { - Assert.NotNull(entry.Name); - Assert.True(Enum.IsDefined(entry.EntryType)); - Assert.True(Enum.IsDefined(entry.Format)); - - if (entry.EntryType == TarEntryType.Directory) - continue; - - var ds = entry.DataStream; - if (ds != null && ds.Length > 0) - { - using var memoryStream = new MemoryStream(); - ds.CopyTo(memoryStream); - } + using var memoryStream = new MemoryStream(); + ds.CopyTo(memoryStream); } } }