Skip to content

Commit

Permalink
[release/9.0] [Tar] Fill in the file size even if the file is empty. (#…
Browse files Browse the repository at this point in the history
…107633)

* [Tar] Fill in the file size even if the file is empty. This matches standard behavior.

* fix tests, set size only when datastream is not null

* Add unit tests for size header of an empty file

* Scope disposables

Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com>

* Update test to verify entry can be read after confirming the sequence is correct.
Add test to verify that entries created with the malformed size field are still readable after the bug fix.

---------

Co-authored-by: Szymon Sobik <sobik.szymon@gmail.com>
Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com>
  • Loading branch information
3 people committed Sep 12, 2024
1 parent 593af2b commit c04c2b7
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ private int WriteCommonFields(Span<byte> buffer, TarEntryType actualEntryType)
checksum += FormatNumeric(_gid, buffer.Slice(FieldLocations.Gid, FieldLengths.Gid));
}

if (_size > 0)
if (_dataStream != null && _size >= 0)
{
checksum += FormatNumeric(_size, buffer.Slice(FieldLocations.Size, FieldLengths.Size));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Linq;
using Xunit;

namespace System.Formats.Tar.Tests
Expand Down Expand Up @@ -144,6 +145,74 @@ public void Verify_Checksum_SymbolicLink_LongLink(TarEntryFormat format) =>
public void Verify_Checksum_SymbolicLink_LongLink_LongPath(TarEntryFormat format) =>
Verify_Checksum_Internal(format, TarEntryType.SymbolicLink, longPath: true, longLink: true);

[Fact]
public void Verify_Size_RegularFile_Empty()
{
using MemoryStream archiveStream = new();
string entryName = "entry.txt";
using (TarWriter archive = new(archiveStream, TarEntryFormat.V7, leaveOpen: true))
{
V7TarEntry e = new(TarEntryType.V7RegularFile, entryName)
{
DataStream = new MemoryStream(0)
};
archive.WriteEntry(e);
}

int sizeLocation = 100 + // Name
8 + // Mode
8 + // Uid
8; // Gid
int sizeLength = 12;

archiveStream.Position = 0;
byte[] actual = archiveStream.GetBuffer()[sizeLocation..(sizeLocation + sizeLength)];

byte[] expected = [0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0];
AssertExtensions.SequenceEqual(expected, actual);

archiveStream.Position = 0;
using TarReader reader = new(archiveStream);

TarEntry? actualEntry = reader.GetNextEntry();
Assert.NotNull(actualEntry);
Assert.Equal(0, actualEntry.Length);
Assert.Null(actualEntry.DataStream); // No stream created when size field's value is 0
}

[Fact]
public void Verify_Compatibility_RegularFile_EmptyFile_NoSizeStored()
{
using MemoryStream archiveStream = new();
string entryName = "entry.txt";
using (TarWriter archive = new(archiveStream, TarEntryFormat.V7, leaveOpen: true))
{
V7TarEntry e = new(TarEntryType.V7RegularFile, entryName)
{
DataStream = new MemoryStream(0)
};
archive.WriteEntry(e);
}

int sizeLocation = 100 + // Name
8 + // Mode
8 + // Uid
8; // Gid

// Fill the size field with 12 zeros as we used to before the bug fix
byte[] replacement = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
archiveStream.Seek(sizeLocation, SeekOrigin.Begin);
archiveStream.Write(replacement);

archiveStream.Position = 0;
using TarReader reader = new(archiveStream);

TarEntry? actualEntry = reader.GetNextEntry(); // Should succeed to read the entry with a malformed size field value
Assert.NotNull(actualEntry);
Assert.Equal(0, actualEntry.Length); // Should succeed to detect the size field's value as zero
Assert.Null(actualEntry.DataStream); // No stream created when size field's value is 0
}

private void Verify_Checksum_Internal(TarEntryFormat format, TarEntryType entryType, bool longPath, bool longLink)
{
using MemoryStream archive = new MemoryStream();
Expand Down

0 comments on commit c04c2b7

Please sign in to comment.