diff --git a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs index 510d38a0..9231833d 100644 --- a/src/SharpCompress/Common/Tar/Headers/TarHeader.cs +++ b/src/SharpCompress/Common/Tar/Headers/TarHeader.cs @@ -2,6 +2,7 @@ using System; using System.Buffers.Binary; using System.IO; using System.Text; +using ZstdSharp.Unsafe; namespace SharpCompress.Common.Tar.Headers; @@ -134,9 +135,8 @@ internal sealed class TarHeader hasLongValue = false; } while (hasLongValue); - var crc = ReadAsciiInt64Base8(buffer, 148, 7); - - if (crc != RecalculateChecksum(buffer)) + // Check header checksum + if (!checkChecksum(buffer)) { return false; } @@ -318,6 +318,42 @@ internal sealed class TarHeader (byte)' ' }; + internal static bool checkChecksum(byte[] buf) + { + const int eightSpacesChksum = 256; + var buffer = new Span(buf).Slice(0, 512); + int posix_sum = eightSpacesChksum; + int sun_sum = eightSpacesChksum; + + foreach (byte b in buffer) + { + posix_sum += b; + sun_sum += unchecked((sbyte)b); + } + + // Special case, empty file header + if (posix_sum == eightSpacesChksum) + { + return true; + } + + // Remove current checksum from calculation + foreach (byte b in buffer.Slice(148, 8)) + { + posix_sum -= b; + sun_sum -= unchecked((sbyte)b); + } + + // Read and compare checksum for header + var crc = ReadAsciiInt64Base8(buf, 148, 7); + if (crc != posix_sum && crc != sun_sum) + { + return false; + } + + return true; + } + internal static int RecalculateChecksum(byte[] buf) { // Set default value for checksum. That is 8 spaces. diff --git a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs index 6a8f3294..1024e945 100644 --- a/tests/SharpCompress.Test/Tar/TarArchiveTests.cs +++ b/tests/SharpCompress.Test/Tar/TarArchiveTests.cs @@ -217,7 +217,8 @@ public class TarArchiveTests : ArchiveTests { var archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.Empty.tar"); using Stream stream = File.OpenRead(archiveFullPath); - Assert.Throws(() => ArchiveFactory.Open(stream)); + using var archive = ArchiveFactory.Open(stream); + Assert.True(archive.Type == ArchiveType.Tar); } [Theory]